0%

试题 历届试题 剪格子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
资源限制
时间限制: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

首先列出来这个题有很多特殊情况,其中一种就是下面这个数据。

1
2
3
4
5
4 4
20 20 20 1
1 20 1 1
1 20 1 1
1 1 1 90

这种数据我下面这个代码(网上大部分都是这种直接dfs的)过不了,但是在蓝桥杯官网100分(数据水),

代码一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import java.util.Arrays;
import java.util.Scanner;

public class Main {

public static int[][] vis = new int[15][15];
public static int[][] arr;
public static int[][] dir = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
public static int sum = 0, minCnt = 1000, m, n;
public static void dfs(int x, int y, int curSum, int curCnt) {
//System.out.println(curSum);
if(curSum * 2 >= sum) {
if(curSum * 2 > sum) return ;
if(vis[0][0] == 1) minCnt = Math.min(minCnt, curCnt);
}
for(int i = 0; i < 4; i++) {
int newX = x + dir[i][0];
int newY = y + dir[i][1];
if(newX >= 0 && newX < n && newY >= 0 && newY < m && vis[newX][newY] == 0) {
vis[newX][newY] = 1;
curCnt++;
dfs(newX, newY, curSum + arr[newX][newY], curCnt);
curCnt--;
vis[newX][newY] = 0;
}
}
}

public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
m = sc.nextInt(); n =sc.nextInt();
arr = new int[n][m];

for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
arr[i][j] = sc.nextInt();
sum += arr[i][j];
}
}

if(sum % 2 == 1) {
System.out.print(0);
} else {
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
vis[i][j] = 1;
dfs(i, j, arr[i][j], 1);
vis[i][j] = 0;
}
}
if(minCnt == 1000) System.out.print(0);
else System.out.print(minCnt);
}
sc.close();
}

}

由于过不了那个数据,于是我写了下面这个代码,但是这个代码有个数据会超时,但是算的结果都是对的。

这个代码基本上没办法剪枝(所以我觉得还没有直接0/1暴力好)。

代码二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

class Point{
int x, y;
public Point(int _x, int _y) {
x = _x; y = _y;
}
}

public class Main {

public static int[][] vis = new int[30][30], vis2 = new int[30][30];
public static int[][] arr;
public static int[][] dir = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
public static int sum = 0, minCnt = 1000, m, n;

public static void Update() {
int cnt = 0, curSum = 0;
for(int i = 0; i < 2 * n + 1; i++) {
for(int j = 0; j < 2 * m + 1; j++) {
vis2[i][j] = 0;
}
}
Queue<Point>queue = new LinkedList<>();
queue.add(new Point(1, 1));
vis2[1][1] = 1;
curSum += arr[1][1];
cnt = 1;
while(!queue.isEmpty()) {
Point cur = queue.poll();
for(int i = 0; i < 4; i++) {
int newX = cur.x + dir[i][0];
int newY = cur.y + dir[i][1];
if(newX >= 0 && newX < 2 * n + 1 && newY >= 0 && newY < 2 * m + 1 && vis2[newX][newY] == 0 && vis[newX][newY] == 0) {
queue.add(new Point(newX, newY));
vis2[newX][newY] = 1;
curSum += arr[newX][newY];
if(curSum * 2 > sum) return ;
if(arr[newX][newY] != 0) cnt++;
}
}
}
if(curSum * 2 == sum) minCnt = Math.min(minCnt, cnt);
}

public static void dfs(int x, int y) {
for(int i = 0; i < 4; i++) {
int newX = x + dir[i][0];
int newY = y + dir[i][1];
if(newX >= 0 && newX < 2 * n + 1 && newY >= 0 && newY < 2 * m + 1 && vis[newX][newY] == 0) {
if(arr[newX][newY] == 0) {
vis[newX][newY] = 1;
dfs(newX, newY);
vis[newX][newY] = 0;
} else Update();
}
}
}

public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
m = sc.nextInt(); n =sc.nextInt();
arr = new int[n * 2 + 1][m * 2 + 1];

for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
arr[i * 2 + 1][j * 2 + 1] = sc.nextInt();
sum += arr[i * 2 + 1][j * 2 + 1];
}
}

if(sum % 2 == 1) {
System.out.print(0);
} else {
vis[0][0] = 1;
dfs(0, 0);
if(minCnt == 1000) System.out.print(0);
else System.out.print(minCnt);
}

sc.close();
}

}