问题描述
如下图所示,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
代码如下:
此代码思路为利用深度优先搜索,从左上角格子开始搜索出满足要求的路径
import java.lang.reflect.Array;
import java.util.*;
public class Main {
static int[][] arr;
static boolean[][] vis; // 记录走过的路径,防止重复走上某一格子
static int total = 0;
public static void main(String[] args) {
// 处理输入
Scanner scan = new Scanner(System.in);
int m = scan.nextInt();
int n = scan.nextInt();
arr = new int[n][m];
vis = new boolean[n][m];
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
arr[i][j] = scan.nextInt();
total += arr[i][j];
}
}
// 逻辑处理
int ans = dfs(0, 0, 1, arr[0][0]);
// 输出
System.out.println(ans);
scan.close();
}
// 深度优先搜索,寻找最优解
// i,j为当前格子在数组中的下标,steps代表有几个格子在内,sum为包括左上角第一个元素在内到当前格子的和
static int dfs(int i, int j, int steps, int sum) {
if (vis[i][j]) { // 当前格子已经在路径上,不能重复走某一个格子
return 0;
}
if (sum > total / 2) { // 一定不符合题目要求,剪支
return 0;
}
if (sum == total / 2) { // 恰好满足要求
return steps;
}
// 递归处理
vis[i][j] = true; //标记格子,防止深层递归时继续走该格子
int[] ans = { 0, 0, 0, 0 };
if (i + 1 < arr.length) {
ans[0] = dfs(i + 1, j, steps + 1, sum + arr[i + 1][j]); // 向下
}
if (j + 1 < arr[i].length) {
ans[1] = dfs(i, j + 1, steps + 1, sum + arr[i][j + 1]); // 向右边
}
if (i - 1 >= 0) {
ans[2] = dfs(i - 1, j, steps + 1, sum + arr[i - 1][j]); // 向上
}
if (j - 1 > -0) {
ans[3] = dfs(i, j - 1, steps + 1, sum + arr[i][j - 1]); // 向左
}
vis[i][j] = false; // 标记格子
// 返回
Arrays.sort(ans);
for (int k = 0; k < ans.length; k++) {
if (ans[k] != 0) {
return ans[k];
}
}
return ans[0];
}
}
如上代码在处理类似如下输入时会有问题:
2 2
1 1
1 3
因为是深度优先搜索,所以从左上角一路顺着搜索下去,比如从[0][0]出发到
[0][1],如果发现不行就回溯到[0][0],再往下走到[1][0],这样就不能形成[0][0]->
[0][1]->[1][0]的路径。