Java习题练习:剪格子
- 题目
- 整体思路
- 源代码
- 代码解析
这道题是2013年第四届蓝桥杯 Java A组省赛第九题剪格子
题目
如图p1.jpg所示,3 x 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
再例如:
用户输入:
4 3
1 1 1 1
1 30 80 2
1 1 1 100
则程序输出:
10
(参见p2.jpg)
资源约定:
峰值内存消耗(含虚拟机) < 64M
CPU消耗 < 5000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
图1:
图二:
整体思路
读完题目,我们想到以(0,0)为基点,进行深搜dfs,用递归实现。
在这道题里,每次走动,都有四个方向:上下左右。
最主要的就是这个,其他细节的地方具体看代码解析。
源代码
import java.util.Scanner;
public class Main {
static int[][]g;
static int[][]vis;
private static int n;
private static int m;
private static int total;
private static int ans=Integer.MAX_VALUE;
static void dfs(int i,int j,int steps,int sum) {
if(i<0||i==n||j<0||j==m||vis[i][j]==1) return;
if(sum==total/2) {
ans=Math.min(ans, steps);
return ;
}
if(sum>total/2) return;
vis[i][j]=1;
dfs(i-1,j,steps+1,sum+g[i][j]);
dfs(i+1,j,steps+1,sum+g[i][j]);
dfs(i,j-1,steps+1,sum+g[i][j]);
dfs(i,j+1,steps+1,sum+g[i][j]);
vis[i][j]=0;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in=new Scanner(System.in);
m=in.nextInt();
n=in.nextInt();
g=new int [n][m];
vis=new int [n][m];
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
g[i][j]=in.nextInt();
total+=g[i][j];
}
}
dfs(0,0,0,0);
System.out.println(ans);
}
}
代码解析
4 static int[][]g;
存储输入数组
5 static int[][]vis;
存储访问过的格子
9 private static int ans=Integer.MAX_VALUE;
让ans初始化为一个大数
4~9
这些都是全局变量,在各个函数里面都可以用到
29~30
注意m是列,n才是行
31~32
g=new int [n][m];
vis=new int [n][m];
必须得要初始化才行
32~38
输入存储,并且得到总值total
12 if(i<0||in||j<0||jm||vis[i][j]==1) return;
这是边界条件
12 if(i<0||in||j<0||jm||vis[i][j]==1) return;
边界条件:
下标溢出,以及访问重复
14 ans=Math.min(ans, steps);
取得多个答案较小值
第18行 vis[i][j]=1;
访问过的,进行标记
23 vis[i][j]=0;//走完一个循环,重置
回溯,清零