题目描述
历届试题 剪格子
时间限制: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。
输出格式
输出一个整数,表示在所有解中,包含左上角的分割区可能包含的最小的格子数目。
样例输入
3 3 10 1 52 20 30 1 1 2 3
样例输出
3
分析
用递归算法
首先注意输入,先输入列再输入行
因为要求两部分的数字和相同,所以我们只要求出左上角部分的数字相加等于整个数组的一半就行了
要求求出左上角最小区域的格子数,所以我们从左上角开始计算,找出四周最大的格子相加来递归,如果相加后的数字大于一半总数,就寻找下一个最大的格子,如果四周的格子都不合格,就放弃这个格子。
为了防止被重复计算,设一个数组来将已用的格子记录下来
#include<stdio.h>
int n, m;
int score;
int x[4] = { 0,-1,0,1 };
int y[4] = { -1,0,1,0 };
int After[20][20] = { 0 };//记录已用的格子
void otherCompute(int a[][20], int i, int j, int other[]) {//将周围的格子按从大到小排序
int thisI, thisJ;
int flag = 4;//可用范围
int scores[4] = { 0 };//记录周围数据的大小
int i2;
int j2=0;
for (i2 = 0;i2 < 4;i2++) {//将周围所有数据输入
thisI = i + x[i2];
thisJ = j + y[i2];
if (thisI < 0 || thisI >= n || thisJ < 0 || thisJ >= m|| After[thisI][thisJ]==1) {//范围外的格子与已用的格子报废
scores[flag-1] = -1;//放在最后
other[flag-1] = -1;
flag--;
}
else {
scores[j2] = a[thisI][thisJ];
other[j2] = i2;
j2++;
}
}
for (i2 = 0;i2 < flag;i2++) {//从大到小排序
for (j2 = 0;j2 < i2; j2++) {
if (scores[i2] > scores[j2]) {
int k = scores[i2];scores[i2] = scores[j2];scores[j2] = k;
k = other[i2];other[i2] = other[j2];other[j2] = k;
}
}
}
}
int Compute(int a[][20],int i,int j,int thisScore) {
int other[4] = { 0 };//记录周围数据从大到小的顺序
After[i][j] = 1;
otherCompute(a, i, j, other);
for (int k = 0;k < 4;k++) {
if (other[k] == -1)
break;
thisScore += a[i + x[other[k]]][j + y[other[k]]];
if (thisScore == score) {//得到结果,返回2
return 2;
}
if (thisScore > score) {//数字太大,下一个较小得数
thisScore -= a[i + x[other[k]]][j + y[other[k]]];//还原
continue;
}
int compute = Compute(a, i + x[other[k]], j + y[other[k]], thisScore);//递归
if (compute == -1) //此路不通
continue;
return ++compute;
}
After[i][j] = 0;//此路不通放弃
return -1;
}
int main() {
int i, j;
int a[20][20];
int MAX=0;
scanf("%d %d", &m, &n);
for (i = 0;i < n;i++) {
for (j = 0;j < m;j++) {
scanf("%d", &a[i][j]);
MAX += a[i][j];
}
}
score = MAX / 2;
int End = Compute(a,0,0,a[0][0]);
if (End == -1)
printf("0\n");
else
printf("%d", End);
return 0;
}
如果用C++能简单些,但我不会用,就用的C语言
345

被折叠的 条评论
为什么被折叠?



