问题
如下图所示,3 x 3 的格子中填写了一些整数。
+--*--+--+
|10* 1|52|
+--****--+
|20|30* 1|
*******--+
| 1| 2| 3|
+--+--+--+
我们沿着图中的星号线剪开,得到两个部分,每个部分的数字和都是60。
本题的要求就是请你编程判定:对给定的m x n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等。
如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。
如果无法分割,则输出 0。
例:
输入一个 3 x 3 的数组:
10 1 52
20 30 1
1 2 3
输出:3
题解
-
图
1.算法
- 从左上角第一个格子开始进行深度优先搜索,从上下左右四个方向去进行递归搜索,可以进行递归的条件是 1)要递归的下一个格子为被设置访问标记 2)在数组内,未出界。
- 每走一步,就计算走过的格子的和是多少,再计算没走过的格子的和是多少。如果两个和相等,就代表符合条件,然后我们尝试是否可以更新result(我们需要的答案),如果走过的格子数比result小,就可以更新。
- 最后递归完成后将递归过的格子的访问标记清除。
2.代码(C)
#include <stdio.h>
int a[10][10];
int flag[10][10];//标记数组
int result=10000000;//记录结果
int m,n;//记录数组大小
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};//用于记录四个方向的x,y变化(上左下右)
void dfs(int x,int y,int sum) //x,y记录坐标,sum记录走到这步的和
{
int i,j;
sum=sum+a[x][y];
flag[x][y]=1;
//计算另一部分和
int sum_other=0;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
if(flag[i][j]==0) //0代表没有走过的点
sum_other=sum_other+a[i][j];
}
//判断两部分是否相等
if(sum_other==sum)
{
int num=0; //计算被标记的格子数
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(flag[i][j]==1) num++;
if(num<result) result=num;
return;
}
//向4个方向递归
for(i=0;i<4;i++)
{
int tx=x+dir[i][0];
int ty=y+dir[i][1];
if(x>=0 && x<n && y>=0 && y<m &&flag[tx][ty]==0)
{
dfs(tx,ty,sum);
}
}
flag[x][y]=0; //四个方向全部遍历完都没有解,那么取消标记
}
int main()
{
int i,j;
scanf("%d %d",&m,&n);
for(i=0;i<n;i++) //n行m列
for(j=0;j<m;j++)
scanf("%d",&a[i][j]);
dfs(0,0,0);
printf("%d",result);
return 0;
}