试题 历届试题 剪格子

资源限制

时间限制:1.0s 内存限制:256.0MB

问题描述

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

这里的答案只能通过OJ但是并不是正确的解。这里的解法是一次dfs,搜索所有并且记录最少的格子,但是如果出现下述情况,则不可行:
3
1 1 1
1 2 1
1 1 5
输出会的到0,因为正确的路径是
1 1 1
1 2 1
1 1 5
但是因为从(0,0)点出发,无法达到。
一个暴力的解法就是,遍历所有点作为起点,以是否经过(0,0)点为另一个附加条件进行枚举。这样的话,根据题目的数据规模,最大为100格子,一次dfs最坏情况就是4^100(大致算,每个格子要四个方向),那100次就是 100*4^100。
另外一个想法就是,(0,0)就两个方向,我先往下走一步(dfs中的一步),然后往右dfs。一次结束后。往下再走一步(dfs中的一步),继续循环。

#include<iostream>
#include<vector>
#include<string>
#include<sstream> 
#include<algorithm>
#include<cstring>

using namespace std;
int panel[10][10];
int flag[10][10];
int number = 101;
int m, n;
void dfs(int i, int j, int target, int num)
{
    
    
	if (flag[i][j])
		return;
	if (target - panel[i][j] == 0 && num + 1 < number)
		number = num + 1;
	if (target < panel[i][j])
		return;
	flag[i][j] = 1;
	if (target > panel[i][j])
	{
    
    
		if (i + 1 <= m && !flag[i + 1][j])
			dfs(i + 1, j, target - panel[i][j], num + 1);
		if (j + 1 <= n && !flag[i][j + 1])
			dfs(i, j + 1, target - panel[i][j], num + 1);
		if (i - 1 >= 0 && !flag[i - 1][j])
			dfs(i - 1, j, target - panel[i][j], num + 1);
		if (j - 1 >= 0 && !flag[i][j - 1])
			dfs(i, j - 1, target - panel[i][j], num + 1);
	}
	flag[i][j] = 0;
	return;
}



int main()
{
    
    
	cin >> m;
	cin >> n;
	int sum = 0;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
		{
    
    
			cin >> panel[i][j];
			sum += panel[i][j];
		}
	memset(flag, sizeof(flag), 0);
	dfs(0, 0, sum / 2, 0);
	cout << number;

	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39117858/article/details/104622118
今日推荐