资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
如下图所示,3 x 3 的格子中填写了一些整数。
±-–±-+
|10 1|52|
±-***–+
|20|30 1|
*******–+
| 1| 2| 3|
±-±-±-+
我们沿着图中的星号线剪开,得到两个部分,每个部分的数字和都是60。
本题的要求就是请你编程判定:对给定的m x n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等。
如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。
如果无法分割,则输出 0。
输入格式
程序先读入两个整数 m n 用空格分割 (m,n<10)。
表示表格的宽度和高度。
接下来是n行,每行m个正整数,用空格分开。每个整数不大于10000。
输出格式
输出一个整数,表示在所有解中,包含左上角的分割区可能包含的最小的格子数目。
样例输入1
3 3
10 1 52
20 30 1
1 2 3
样例输出1
3
样例输入2
4 3
1 1 1 1
1 30 80 2
1 1 1 100
样例输出2
10
这里的答案只能通过OJ但是并不是正确的解。这里的解法是一次dfs,搜索所有并且记录最少的格子,但是如果出现下述情况,则不可行:
3
1 1 1
1 2 1
1 1 5
输出会的到0,因为正确的路径是
1 1 1
121
1 15
但是因为从(0,0)点出发,无法达到。
一个暴力的解法就是,遍历所有点作为起点,以是否经过(0,0)点为另一个附加条件进行枚举。这样的话,根据题目的数据规模,最大为100格子,一次dfs最坏情况就是4^100(大致算,每个格子要四个方向),那100次就是 100*4^100。
另外一个想法就是,(0,0)就两个方向,我先往下走一步(dfs中的一步),然后往右dfs。一次结束后。往下再走一步(dfs中的一步),继续循环。
#include<iostream>
#include<vector>
#include<string>
#include<sstream>
#include<algorithm>
#include<cstring>
using namespace std;
int panel[10][10];
int flag[10][10];
int number = 101;
int m, n;
void dfs(int i, int j, int target, int num)
{
if (flag[i][j])
return;
if (target - panel[i][j] == 0 && num + 1 < number)
number = num + 1;
if (target < panel[i][j])
return;
flag[i][j] = 1;
if (target > panel[i][j])
{
if (i + 1 <= m && !flag[i + 1][j])
dfs(i + 1, j, target - panel[i][j], num + 1);
if (j + 1 <= n && !flag[i][j + 1])
dfs(i, j + 1, target - panel[i][j], num + 1);
if (i - 1 >= 0 && !flag[i - 1][j])
dfs(i - 1, j, target - panel[i][j], num + 1);
if (j - 1 >= 0 && !flag[i][j - 1])
dfs(i, j - 1, target - panel[i][j], num + 1);
}
flag[i][j] = 0;
return;
}
int main()
{
cin >> m;
cin >> n;
int sum = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
{
cin >> panel[i][j];
sum += panel[i][j];
}
memset(flag, sizeof(flag), 0);
dfs(0, 0, sum / 2, 0);
cout << number;
return 0;
}