博主今年大三了,最近报名了一个蓝桥杯的个人项的java组。所以博主最近在刷题,且博主会把一些自认为比较好的题目拿出来跟大家分享一下(发出来的代码都是博主自己敲的,且都正确,这个大家就放心了)。
问题描述:
问题分析:
这个问题我是采用深度优先遍历来解决的。每次填入一个数字,确保符合相邻的数字在方格子中不相邻。当格子填完的时候就是一种情况(注意数字不能重复)。
数据域:
1. private static int[] visited;
用来存储数据0-9的状态,0表示未被访问,1表示已经被访问过了。
2. private static int[][] dir= {{-1,-1},{-1,0},{0,-1},{-1,1}};
方向数组用来表示被监测点的四周的点。
比如原数组的坐标为(x,y),经过 dx=x+dir[0][0]; dy=y+dir[0][1]的操作后,坐标(dx,dy)就在原先坐标的左上角。
可以用一个for循环把该数组的八个方向都给遍历了(虽然实际上并不需要遍历这么多的点)。
3.private static int[][] save;
存储方格子里面的数字(0-9,且数字不能重复)。
4.private static int sum;
用来表示符合的个数,没出现一个符合的情况执行sum++操作。
注意:由于这是在java里面,主函数是static类型的,所以所有的数据和方法都必须是static类型的(java里面不允许静态类访问非静态的数据和方法)。
下面是处理这几个问题的方法(c以及c++里面叫函数,但java里面都是统一叫方法)。
1.数据的初始化
private static void init() {
visited=new int[10];
for(int i=0;i<10;i++) {
visited[i]=0;//0表示尚未访问,1表示已经被访问过了
}
sum=0;
save=new int[3][4];
for(int i=0;i<3;i++) {
for(int j=0;j<4;j++) {
save[i][j]=0;
}
}
save[0][0]=-10;
save[2][3]=-10;
}
这里面要注意一点:事实上,(0,0)和(2,3)这两点并不在不在方格子里面,但如果把(0,0)点所在的数据赋值为0且(0,1)的数据赋值为1,那么他们两个不满足相邻数字子在方格子里面不相邻的情况,从规定上来说,不能给(0,1)点赋值1.而实际上点(0,0)压根不在方格的范围之内,也就是说点(0,0)不应该参与计算。所以为了避免这种情况我们可以把这两点的数据夸张一些,避免偶然性。
2.判断数据是否越界
private static boolean border(int x,int y) {
if(x>=0&&x<3&&y>=0&&y<4) {
return true;
}
return false;
}
这里面我们可以看到由于博主的偷懒原本不在方格内的这两点博主并没有排除掉,所以在上面赋值的时候要把那两点的数据写的大一点,避免偶然性。
3.判断是否满足相邻数字在方格中不相邻的情况
private static boolean check(int x,int y,int k) {
int dx,dy;
for(int i=0;i<4;i++) {
dx=x+dir[i][0];
dy=y+dir[i][1];
if(border(dx,dy)==true&&Math.abs(k-save[dx][dy])==1) {
return false;
}
}
return true;
}
x,y代表要监测点的位置,k代表要填入监测点的数字(如果满足填入该数字,不满足的话选取另外一个没有被访问过的数字)。
事实上并不需要遍历所有方向,只需遍历几个方向就够了。
4.dfs(int x,int y)
private static void dfs(int x,int y) {
if(x==2&&y==3) {
sum++;
}
else {
for(int i=0;i<10;i++) {
if(visited[i]==0&&check(x,y,i)==true) {//该元素未被访问
save[x][y]=i;
visited[i]=1;
if(y<3) {
dfs(x,y+1);
}
else {
dfs(x+1,0);
}
visited[i]=0;
}
}
}
这就是一个简单的深度搜索问题,里面用到了递归和回溯的方法,很常见,就不多说了。需要注意的是递归的时候y<3(我当时写成了y<4,结果编译显示数组越界,傻fufu的)。
最终答案:1580