题目:
如下图所示,3 x 3 的格子中填写了一些整数。
我们沿着图中的星号线剪开,得到两个部分,每个部分的数字和都是60。
本题的要求就是请你编程判定:对给定的m x n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等。
如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。
如果无法分割,则输出 0。
程序先读入两个整数 m n 用空格分割 (m,n<10)。
表示表格的宽度和高度。
接下来是n行,每行m个正整数,用空格分开。每个整数不大于10000。
首先求出所有节点和的一半sum,从左上角那个点一次向后进行回溯+剪枝搜索,如遇到所经过结点和等于sum,则将深度deep加入优先级队列(使用优先级队列可以在最后直接peek得出最小深度)。
回溯采用dfs的方法,剪枝条件有
(1)所经过结点和大于sum
(2)所经过结点和等于sum
(3)结点x,y坐标超出矩阵边界
(4)当前结点之前已经到达过,即b[x][y] == true
代码如下:
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
public class Main {
// 总和的一半
static int num;
// 行数
static int hang;
// 列数
static int lie;
// 存放数据
static int[][] mix;
// 记录某个结点是否在当前路径下已经被访问,false表示未访问,true表示已访问
static boolean[][] b;
// 当前路径所经过结点和
static int sum = 0;
// 优先队列
static Queue<Integer> queue = new PriorityQueue<Integer>();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
lie = sc.nextInt();
hang = sc.nextInt();
mix = new int[hang][lie];
b = new boolean[hang][lie];
int temp = 0;
for (int a = 0; a < hang; a++) {
for (int b = 0; b < lie; b++) {
mix[a][b] = sc.nextInt();
temp += mix[a][b];
}
}
num = temp >> 1;
sc.close();
dfs(0, 0, 1);
System.out.println(queue.peek() == null ? 0 : queue.peek());
}
/**
* 回溯矩阵所有结点
* @param x
* @param y
* @param deep
*/
private static void dfs(int x, int y, int deep) {
if (x < 0 || x >= hang || y < 0 || y >= lie || b[x][y]) {
return;
}
if ((sum + mix[x][y]) > num) {
return;
}
if ((sum + mix[x][y]) == num) {
queue.add(deep);
return;
}
sum += mix[x][y];
b[x][y] = true;
dfs(x - 1, y, deep + 1);
dfs(x, y - 1, deep + 1);
dfs(x + 1, y, deep + 1);
dfs(x, y + 1, deep + 1);
sum -= mix[x][y];
b[x][y] = false;
}
}原文地址:http://blog.csdn.net/u011333588/article/details/45934799