题目:
如下图所示,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