蓝桥杯 历届试题 PREV-4 剪格子

问题描述

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

 

思路分析:从题目和两个案例可以看出,本题是典型的dfs(深度优先搜索)算法的题目。采用dfs+回溯的思路,从数组左上角即(0,0)开始搜索,累加当前数字,直到数字和为总数字和的一半,返回走到数组当前位置的步数。值得说明的是,本题先读入的m是列,而不是n(行)。具体思路请看代码,附带详细注释。

 

import java.util.Scanner;

/**
 * 
 * Created with MyEclipse
 * 
 * @Description 蓝桥杯 历届试题 PREV-4 剪格子
 * @author Jun
 * @date 2020年4月16日
 */
public class Problem04 {

	static int[][] dir = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } }; // 方向右,下,左,上
	static boolean[][] user;
	static int[][] map;
	static n, m, ans = Integer.MAX_VALUE, sum = 0;

	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		m = scan.nextInt();
		n = scan.nextInt();
		user = new boolean[n][m];
		map = new int[n][m];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				map[i][j] = scan.nextInt();
				sum += map[i][j];
			}
		}
		if (sum % 2 == 0) { // 和为偶数
//			for (int i = 0; i <= n/2; i++) {
//				for (int j = 0; j < m/2; j++) {
//					user[i][j]=true;
//					int temp = dfs(i, j, map[i][j]);
//					user[i][j]=false;
//					if (temp != 0) { // 获取所有结果中的最小值
//						ans = Math.min(ans, temp);
//					}
//				
//				}
//			}
			user[0][0] = true;
			System.out.println(dfs(0, 0, map[0][0]));
//			System.out.println(ans);
		} else {
			System.out.println(0);
		}

	}

	public static boolean checkNext(int x, int y, int num) { // 检查(x,y)是否允许走
		if (x < 0 || x >= n || y < 0 || y >= m) { // 数组越界
			return false;
		}
		if (user[x][y]) { // 该位置元素操作过
			return false;
		}
		if (num + map[x][y] > sum / 2) { // 走这一步超过了和的一半
			return false;
		}
		return true;

	}

	public static int dfs(int x, int y, int num) { // 代表搜索完点(x,y)时左上角的和sum
		if (num == sum / 2) {
			return 1;
		}
		for (int i = 0; i < 4; i++) {
			int nx = x + dir[i][0], ny = y + dir[i][1]; // 下一个点的坐标
			if (!checkNext(nx, ny, num)) { // 下一个点不可以走
				continue;
			}
			// 下一步可以走
			user[nx][ny] = true;
			int res = dfs(nx, ny, num + map[nx][ny]); //dfs,递归探查下一个点
			if (res != 0) { // 产生结果,直接返回
				return res + 1;
			}
			user[nx][ny] = false;  //回溯
		}
		return 0;

	}

}

参考:https://www.cnblogs.com/yym2013/p/3526167.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值