歡迎訪問我的新博客:http://www.milkcu.com/blog/
原文地址:http://www.milkcu.com/blog/archives/2014pa10.html
引言
這是2013年第四屆藍橋杯全國軟件大賽預賽A組(C/C++組)第9題,爲編程題,方法是深度優先搜索(DFS)。
題目描述
標題:剪格子
如圖p1.jpg所示,3 x 3 的格子中填寫了一些整數。
我們沿着圖中的紅色線剪開,得到兩個部分,每個部分的數字和都是60。
本題的要求就是請你編程判定:對給定的m x n 的格子中的整數,是否可以分割爲兩個部分,使得這兩個區域的數字和相等。
如果存在多種解答,請輸出包含左上角格子的那個區域包含的格子的最小數目。
如果無法分割,則輸出 0
程序輸入輸出格式要求:
程序先讀入兩個整數 m n 用空格分割 (m,n<10)
表示表格的寬度和高度
接下來是n行,每行m個正整數,用空格分開。每個整數不大於10000
程序輸出:在所有解中,包含左上角的分割區可能包含的最小的格子數目。
例如:
用戶輸入:
3 3
10 1 52
20 30 1
1 2 3
則程序輸出:
3
再例如:
用戶輸入:
4 3
1 1 1 1
1 30 80 2
1 1 1 100
則程序輸出:
10
(參見p2.jpg)
資源約定:
峯值內存消耗 < 64M
CPU消耗 < 5000ms
請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多餘內容。
所有代碼放在同一個源文件中,調試通過後,拷貝提交該源碼。
注意: main函數需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要調用依賴於編譯環境或操作系統的特殊函數。
注意: 所有依賴的函數必須明確地在源文件中 #include <xxx>, 不能通過工程設置而省略常用頭文件。
提交時,注意選擇所期望的編譯器類型。
分析
本題的主要思路是深度優先搜索,但要注意一次深度優先搜索結束後的狀態恢復。
題目給出的“挖洞剪法也可”,更加肯定了DFS的正確性。
雖然是倒數第二題,難度並沒那麼大。
代碼實現
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#define MAXMN 20
using namespace std;
int m, n;
int sum;
int map[MAXMN][MAXMN];
int vis[MAXMN][MAXMN];
vector<int> v;
int cnt = 0;
int sumd = 0;
void print(int x) {
cout << x << " ";
}
void dfs(int x, int y) {
if(vis[x][y]) {
return;
}
vis[x][y] = 1;
cnt++;
sumd += map[x][y];
if(sumd * 2 == sum) {
v.push_back(cnt);
return;
}
for(int i = -1; i <= 1; i++) {
for(int j = -1; j <= 1; j++) {
if(i == j) {
continue;
}
int newx = x + i;
int newy = y + j;
if(newx >= 0 && newx < n && newy >= 0 && newy < m) {
dfs(newx, newy);
}
}
}
sumd -= map[x][y];
cnt--;
vis[x][y] = 0;
}
int main(void) {
cin >> m >> n;
sum = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
cin >> map[i][j];
sum += map[i][j];
}
}
if(sum % 2 == 1) {
cout << "0" << endl;
return 0;
}
memset(vis, 0, sizeof(vis));
dfs(0, 0);
//for_each(v.begin(), v.end(), print);
cout << *min_element(v.begin(), v.end()) << endl;
return 0;
}
(全文完)