更多JAVA版答案移步我的博客:蓝桥杯JAVA版答案汇总
本题考查
深搜(可以适当加入剪枝)、回溯
思路
- 总体思路:从左上角元素开始,每次探测其上下左右四个元素是否可以访问,若可以访问递归访问该元素。
- 如何判断这个块是否合法:若块内元素的和等于给定元素总和的一半即合法,因为题目要求两块元素相等,也就是块内元素等于快外元素,即块内元素和等于总和的一半
- 是否需要判断块内元素是否连通:不需要,在本代码的dfs思路下,每一次dfs都只是从当前块最后加入的元素的位置进行探查,能保证加入块的元素一定与块是联通的,也就是说不存在新加入的元素与块的边界不相邻的情况。
举个例子:当前块内元素(0,0)、(0,1),此时(0,1)是最后加入块的元素,故从(0,1)开始对其四个方位进行探查,而新加入的元素一定与(0,1)邻接,所以保证每一次新加入的元素都与块连通,保证了块的连通性。 - 是否需要判断快外元素连通:不需要,因为只要块内元素连通,可以将块内元素一次性剪下来,此时块外元素也一定在剩余的纸张上,所以块内元素连通等价于块外元素连通。
AC代码
import java.util.Scanner;
public class Main {
static int[][] matrix; //记录元素
static boolean[][] flag; //标识元素是否被访问过,被访问过为true,否则为false
static int m; //列数
static int n; //行数
static int totalSum=0; //记录给定元素的总和,便于比较当前块内元素和是否到达totalSum的一半
static int result = 99999; //记录合法块内元素最小个数
static void dfs(int row, int col, int num, int preSum) {
preSum+=matrix[row][col];
if(preSum==totalSum/2&&num<result) result=num;
if(preSum>totalSum) return; //剪枝
flag[row][col] = true;
if (row - 1 >= 0 && !flag[row - 1][col])
dfs(row - 1, col, num+1, preSum);
if (row + 1 < n && !flag[row + 1][col])
dfs(row + 1, col, num+1, preSum);
if (col - 1 >= 0 && !flag[row][col - 1])
dfs(row, col - 1, num+1, preSum);
if (col + 1 < m && !flag[row][col + 1])
dfs(row, col + 1, num+1, preSum);
flag[row][col] = false; //回溯
}
public static void main(String[] args) {
Scanner scaner = new Scanner(System.in);
m = scaner.nextInt();
n = scaner.nextInt();
matrix = new int[n][m];
flag = new boolean[n][m];
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++) {
matrix[i][j] = scaner.nextInt();
totalSum+=matrix[i][j];
}
scaner.close();
if(totalSum%2!=0) System.out.println("0");
else {
dfs(0,0,1,0);
if(result==99999) System.out.println("0");
else System.out.println(result);
}
}
}