迷宫问题
给一个迷宫,从起点开始找一条到终点的路径。
用二维数组来表示一个迷宫
规定1为迷宫的墙,2为走过的路径,3为不可行的路径。
public class Maze {
//初始化迷宫
static int[][] maze = new int[8][8];
public static void main(String[] args) {
//1表示墙,0表示未被踩踏,2表示走过的路径,3表示走过后发现走不通
for (int i=0; i<8; i++){
maze[i][0] = 1;
maze[i][7] = 1;
}
for (int i=0; i<8; i++){
maze[0][i] = 1;
maze[7][i] = 1;
}
maze[3][3] = 1;
maze[3][4] = 1;
maze[3][5] = 1;
maze[3][6] = 1;
}
}
迷宫的初始图
选择路线并判断的方法
首先要设置起点和终点。
起点为(1,1),即第二行第二列。终点为(6,5)。
其次需要一个选择方向的顺序来进行下一步的操作,这个方法选择的是右下左上的顺时针方法。
如果终点坐标的值为2,说明走出了迷宫,递归可以结束了。
否则,判断当前传入的坐标的值
1.如果是0,说明从未涉足。可以假设当前坐标可以通行,将其设置为2.然后根据方向顺序进行递归。如果四个方向都无法通行,则将其设置为3
2.如果是1,2,3则都返回为false。
/**
* 根据右,下,左,上的顺序来选择路线
*/
public static boolean findWay(int i, int j){
boolean flag = false;
if (maze[6][5] == 2){
return true;
}else {
switch (maze[i][j]){
//如果从未被踩踏
case 0:
maze[i][j] = 2;//假设可以通行
if (findWay(i,j+1)){//向右可以通行
flag = true;
break;
}else if (findWay(i+1,j)){//向下可以通行
flag = true;
break;
}else if (findWay(i,j-1)){//向左可以通行
flag = true;
break;
}else if (findWay(i-1,j)){//向上可以通行
flag = true;
break;
}
maze[i][j] = 3;//说明这点不可通行
return false;
//如果是墙
case 1 :flag = false;
break;
//如果是走过的可行的路
case 2 :flag = false;
break;
//如果是走过的不可行的路
case 3 :flag = false;
break;
}
return flag;
}
}
findWay2(1,1);
调用此函数,参数为起点,最后递归完成时就会有一条路线。
如果选择的顺序方向不同,路径也会改变,比如当顺序为下上左右时,路劲就会很曲折。
最短路径
关于最短路径可以尝试不同的方向顺序组合,设置一个计数器记录一共走了多少步,最少的便是最短路径。
八皇后问题
在 8×8 格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
首先要设计的当然是棋盘,但是可以用一个巧妙的数组来设计。比如:
array[7 ,3 ,0 ,2 ,5 ,1 ,6 ,4 ]
这个数组下标Q表示第Q+1个皇后,坐标是第Q+1行,第array[Q]+1列。
上面可以解读为第一个皇后放在第1行第8列,第二个皇后放在第2行第4列…
static int max = 8;
static int count = 0;//记录解法个数
static int[] location = new int[max];//皇后的位置数组
设计一个方法,判断第n个皇后和前面的所有皇后是否冲突(即任意两个皇后都不能处于同一行、同一列或同一斜线上)。
/**
* 判断第n+1个皇后是否与前面的冲突
*/
private static boolean judge(int n){
boolean flag = true;
for (int i=0; i<n; i++){
//1.两个皇后不能在同一列 2.两个皇后不能在同一斜线
if (location[i] == location[n] || Math.abs(n-i) == Math.abs(location[n]-location[i]))
flag = false;
}
return flag;
}
这里判断的第二个条件可以理解为两个坐标之间斜率不能为1或者-1,也就是不能在同一斜线。
有了判断条件后就可以设置递归函数了。
先写出打印解法数组的函数。
/**
* 打印一种解法
*/
private static void print(){
for (int i = 0; i<location.length; i++){
System.out.print(location[i]+" ");
}
System.out.println();
}
递归函数
递归终止条件是放置第九个皇后的时候。
调用函数时设置形参n=0
也就是先放第一个皇后,放在第1行第1列。for循环固定执行8次循环
- 第一次循环第一个皇后被放在了(0,0)上,显然不冲突
- 递归开始放第二个皇后,又会进入for循环。第二个皇后被放在了(1,0)上,冲突了,则不会进行递归,而是将第二个皇后放在(1,1)上再次判断…
private static void solve(int n){
//如果n等于8,说明放第9个皇后,此时已经解出了一种解法
if (n == 8) {
print();
count++;
return;
}
for(int i=0; i<max; i++){
//把第n+1个皇后放在第i列
location[n] = i;
//如果不冲突,递归继续放第n+2个
if (judge(n)){
solve(n+1);
}
//如果冲突,当前的皇后向右移
}
}
如果成功得出了一种解法就会return,此时又会回溯到某一个节点,此节点继续向右移动开始试错。所以当回溯到第一个皇后并且执行完8次循环后,所有解法就全部打印出来了。
public static void main(String[] args) {
solve(3);
System.out.println(count);;
}
一共是92种摆法。
每次递归都看的异常头疼,所以每次都要debug才能最终想通,哎 。