蓝桥杯——剪格子题解

文章目录

题目

如下图所示,3 x 3 的格子中填写了一些整数(注意是整数!)。

|10*  1|52|
+--****--+
|20|30*  1|
*******--+
|  1|  2|  3|
+--+--+--+ 

在这里插入图片描述

我们沿着图中的星号线剪开,得到两个部分,每个部分的数字和都是60。

本题的要求就是请你编程判定:对给定的m x n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等
如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。
如果无法分割,则输出 0。

分析

因为如果有解答的话,要求输出包含左上角格子的那个区域包含的格子的最小数目,所以我们只需要从左上角的格子开始找符合要求的区域即可;

又因为要把m x n的格子分割为两个部分,使得这两个区域的数字和相等,所以两个区域的数字和等于总的数字和除以2。

说明:
总的数字和有两种情况,一是奇数,二是偶数
①奇数时,比如5, 5 ÷ 2 = 2.5 5÷2=2.5 5÷2=2.5,因为格子都是整数,所以找不到,输出0
②偶数时,可以找到。

我们采用从左上角的格子出发,做深搜;每次记录此次搜索的格子数,直到找到的格子里的数字和等于总数字和的一半,返回,如果此时的格子数少于之前,更新答案。

代码

#include<iostream>
#include<limits>

using namespace std;

int m, n, ans = INT_MAX, target;	//m,n为格子的列数和行数,ans是区域包含的
									//格子的最小数目,target等于格子数字总和的一半
									
int Next[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };	//右下左上四个方向
int table[10][10];	//table数组为n×n大的格子,m,n最大不超过10(题目规定的范围)
bool book[10][10];	//table的标记数组,一开始里面全是false

//深搜
void findMin(int now,int x,int y,int step) {	//now为当前搜索的格子里的数的和,
												//x、y为坐标(左上为0.0),														
												//step为当前深搜里有的格子数
	
	//返回条件
	if (now == target) {
		if (ans > step) 	//更新ans为当前找到的符合要求所用的最小格子数
			ans = step;
		return;
	}
	if (now > target || step > ans)
		return;
	
	//尝试四个方向(常规的深搜操作)
	for (int i = 0; i < 4; i++) {
		int nx, ny;

		nx = x + Next[i][0];
		ny = y + Next[i][1];
		if (nx < 0 || ny < 0 || nx >= n || ny >= m || book[nx][ny] == true)
			continue;

		book[nx][ny] = true;
		findMin(now + table[nx][ny], nx, ny, step + 1);
		book[nx][ny] = false;
	}
}

int main() {
	ios::sync_with_stdio(false);	//只用了cin和cout输入输出的
									//加上这句可一定程度地加快速度
	
	//输入格子
	cin >> m >> n;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++) {
			cin >> table[i][j];
			target += table[i][j];
		}
	
	target /= 2;	//初始化target
	book[0][0] = true;	//标记左上角这个格子,为深搜做准备
	findMin(table[0][0], 0, 0, 1);
	
	//按要求输出
	if (ans != INT_MAX)
		cout << ans;
	else
		cout << 0;

	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值