问题描述
在8x8格的国际象棋棋盘上拜访八个皇后,使其不能相互攻击,即:任意两个皇后都不能处于同一行、同一列或同一斜线上。问有多少中摆法。
思路分析
- 第一个皇后放在第一行第一列
- 第二个皇后放在第二行第一列,然后判断是否合理(不能相互攻击),如果不合理,继续放在第二列、第三列、依次把所有列找完,直到找到一个合适的
- 继续放置第三个皇后,放在第三行的第一列、第二列…直到第八个皇后也被放在一个不冲突的位置,算是找到了一个正确的解。
- 当得到一个正确解时,再更改第八个皇后的位置,找到 在前七个皇后位置保持不变条件下 的所有解;然后从第八个皇后回退到第七个皇后,在前六个皇后的位置保持不变条件下,为第七个皇后寻找新的合理位置,找到后再找对应新的第七位置的第八个皇的合理位置。当第七个皇后所有位置尝试完毕后,再回退到第六个皇后位置,在新的第六个位置下,在为第七、第八找合理位置…直到回退到第一个皇后位置
- 回退到第一个皇后位置后,将第一个皇后放在第一行第二列,然后循环执行1.2.3.4步,然后又回到第5步,再更改第一个皇后的位置…直到尝试完所有可能的位置。
代码
/**
* 递归解决8皇后问题
* @author dxt
*
*/
public class TestQueue8 {
public static void main(String[] args) {
Queue8 q = new Queue8();
q.solve();
}
}
class Queue8{
//定义一个数字表示有多少个皇后
int max = 8;
//定义一个数组,表示一个解中皇后的位置,其中array[i] 表示第i个皇后在第i行第array[i]列
int[] array = new int[max];
/**
* 判断第n个皇后的位置是否合理
* @param n
* @return
*/
private boolean valid(int n) {
for(int i=0; i<n; i++) {
//如果在同一列,或45°、135°的斜线上,则返回false
if(array[i] == array[n] || Math.abs(n-i) == Math.abs(array[n]-array[i])) {
return false;
}
}
return true;
}
/**
* 放置第n个皇后
* @param n
*/
private void check(int n) {
//皇后序列从0开始,当n==max时,其实已将max个皇后放置完毕
if(n == max) {
//第max个皇后已放置完毕,即已得到一个放置结果,输出此结果,并返回
for(int i=0; i<max; i++) {
System.out.print(array[i]+" ");
}
System.out.println();
return;
}
//还没有放置完毕毕,则放置第n个皇后
for(int i=0; i<max; i++) {
//先把第n个皇后放到第n行,第i列
array[n] = i;
//然后判断是否冲突
if(valid(n)) { //不冲突
//则放置第n+1个皇后
check(n+1);
}
//如果冲突,会通过循环找一个不冲突的
}
//得到一个正确解后,会从第max个皇后位置返回,然后通过for循环为第max-1个皇后找一个新的位置
}
/**
* 从第0个开始放置,解决8皇后问题
*/
public void solve() {
check(0);
}
/**
* 重写toString方法,输出一个正确解
*/
public String toString() {
String result = "";
for(int n : array) {
result += n + " ";
}
result += "\n";
return result;
}
}
总结
递归代码贼简单,但写出来是真的难,估计下次遇到一个新的递归问题还是不会,该不会是一生之敌吧。。。