题目
要在8*8的国际象棋棋盘中放8个皇后,使任意两个皇后都不能互相吃掉。规则是皇后能吃掉同一行、同一列、同一对角线的棋子。
下图是符合摆放的一种情况
开始的思路是二维深搜,果然超时不行,没有注意题目特点,明显的回溯递归(相邻两层互不相同,相互影响)
理解回溯算法中对每层的操作即可,题意要求相邻两个皇后,不能在同一层,则可等价于在每层递归填一个数即可,递归树的宽度为8。
我们设层数为x,则在该层有皇后对应的列为arr[x],就实现了二维简化为一维(不同行交给递归处理)
判断条件是否符合摆放规则:
- 同行:每层递归就保证了不同行、
- 同列,arr[x]与每层赋的列值j不同
- 同对角线:两坐标斜率绝对值为1(y1-y2=x1-x2) 注意用绝对值
for (int k=0;k<i;k++){//对0~i行的数进行判断
if (arr[k]==j||Math.abs(arr[k]-j)==Math.abs(i-k)){
flag=false;
}
}
return flag;
代码实现
package 递归与回溯;
import java.util.Map;
//八皇后问题
public class Test01 {
//棋盘放置,可以用一维简化,下标表行数,值表列数,回溯搜素不同行
//对应点的坐标即为 (x,arr[x])和(y,arr[y])
static int []arr;
private static int ans;
public static void main(String[] args) {
arr=new int[8];
dfs(0);
System.out.println(ans);
}
private static void dfs(int i) {
if (i==8){
ans++;
return;
}
for (int j = 0; j < 8; j++) {
if (isok(i,j)){
arr[i]=j;//在第i行第j列放置
dfs(i+1);
arr[i]=0;
}
}
}
private static boolean isok(int i,int j) {//第j列
boolean flag=true;
for (int k=0;k<i;k++){//0~7列判断
if (arr[k]==j||Math.abs(arr[k]-j)==Math.abs(i-k)){
flag=false;
}
}
return flag;
}
}