首页 > 技术文章 > 历届试题 剪格子

henuliulei 2019-02-28 23:25 原文

问题描述

如下图所示,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,并且题目给出数组的大小不大于10*10,所以基本不用担心超时的问题,我们可以考虑通过dfs找出所有的切割方法,保证整个大方格分为两块,且两块的数字之和大小相等,这时记录包含左上角的那个格子所在的一个
大格子含有多少个小格子,记录下来,和之后的情况的答案作对比,取最小值。先看一下我的版本一的代码:
 1 import java.util.Scanner;
 2     public class Main{   
 3         static int sum1=0;
 4         static int sum2=0;
 5         static int  sum=0;
 6         static int min=10000;
 7         static int m;
 8         static int n;
 9         static int array[][]=new int[10][10];
10         public static void main(String[] args) {
11             Scanner scanner=new Scanner(System.in);
12             m=scanner.nextInt();
13              n=scanner.nextInt();
14             for (int i = 0; i <n; i++) {
15                 for (int j = 0; j <= m; j++) {
16                     if(j==0) {
17                         array[i][j]=0;
18                         continue;
19                     }
20                     array[i][j]=scanner.nextInt();
21                 }
22             }
23             sum(0);
24             if(min==10000) {
25                 System.out.println(0);
26             }
27             else {
28                 System.out.println(min);
29             }
30             
31             
32         }
33         public static void sum(int a)
34         {
35             if(a==n) {
36                 //System.out.println(sum1+"----"+sum2);
37                 if(sum1==sum2) {
38                     if(sum<min) {
39                         min=sum;
40                     }
41                 }
42             }else {
43                 for (int i = 0; i <=m; i++) {
44                     sum2+=array[a][i];
45                 }
46                 int ss=sum1;
47                 for(int i=0;i<=m;i++) {
48                     sum1+=array[a][i];
49                     if(i!=0) sum++;
50                     sum2-=array[a][i];
51                     sum(a+1);
52                 }
53                 sum-=m;
54                 sum1=ss;
55             }
56         }
57     }
58     

运行这个代码,我发现所给的测试用例答案都可以通过,可是系统给的测试用例通过不了,分析发现我的代码实现了每行所取的块都是连续的,即不能跳着取,比如下面的一种

1 1 1

1 8 1

1  1 1

我们可以把中间的8作为单独一块,外面的作为另一块,这样中间一行取的块是最左和最右的,跳过了中间的8,但是我的代码是每行从左到右取,所以出现了问题。

版本2的思路是仍然是dfs,不过是按着先右再上再左再下的步骤走这些格子,左上角的格子出发,一直向右走,把走过的路标记,到最顶端到达边界,再向上走,没路,向左,路已经走过,则向下,这样一直递归迭代下去,直到遇到走过的格子总和为所有格子的总数的一半,记录所包含的格子数,继续递归迭代,直到求得最小值解。

代码如下

 1 import java.util.Scanner;
 2     public class Main{   
 3         static int map[][]=new int[20][20];
 4         static int vis[][]=new int[20][20];
 5         static int dx[]= {1,0,-1,0};
 6         static int dy[]= {0,1,0,-1};
 7         static int m,n,s;
 8         static int min1=9999999;
 9         static int ans=1;
10     public static void main(String[] args) {
11         
12         Scanner scanner=new Scanner(System.in);
13          m=scanner.nextInt();
14          n=scanner.nextInt();
15         int sum1=0;
16         for (int i=0;i<n;i++)
17             for (int j=0;j<m;j++)
18             {
19                 map[i][j]=scanner.nextInt();
20                 sum1+=map[i][j];
21             }
22 
23         if (sum1%2!=0) 
24         System.out.println(0);
25         else if (sum1/2==map[0][0]) System.out.println(1);
26         else
27         {
28             s=sum1/2;
29             vis[0][0]=1;
30             dfsn(0,0,map[0][0]);
31             System.out.println(min1);
32         }
33         
34     }
35     static void dfsn(int x,int y,int sum)
36     {
37         if (sum==s)
38         {
39             if(ans<min1){
40                 min1=ans;
41             }
42         }
43         int i;
44         for (i=0;i<4;i++)
45         {
46             int nx=x+dx[i];
47             int ny=y+dy[i];
48             if (0<=nx && nx<n && 0<=ny && ny<m )
49             {
50                 if (sum+map[nx][ny]<=s && vis[nx][ny]!=1)
51 
52                 {
53                     vis[nx][ny]=1;
54                     ans++;
55                     int a=sum+map[nx][ny];
56                     dfsn(nx,ny,a);
57                     ans--;
58                     vis[nx][ny]=0;//初始化标志
59 
60                 }
61 
62             }
63 
64         }
65 
66     }
67    
68    }
69     
70   
71     

 

推荐阅读