今天看了一道国际象棋的布局问题,码界称之为“N皇后”问题,十分有趣。采用递归思想,不断探索和回溯,解法暴力之极。这里分享当棋盘不大的时候,基础的N皇后问题实现代码。思路藏在注释里面啦~
主要是校验的时候有两点比较重要:
- 不同行和不同列就是说,arr[i]不能等于arr[a],因为一行只能放一个,一列只能放一个。
- 不在同一条斜线上就是说,|i-a|不能等于|arr[i]-arr[a]|
题目描述
N皇后问题是指在N∗N的棋盘上要摆N个皇后(1<=n<=14)
要求:任何两个皇后不同行,不同列也不在同一条斜线上,求给一个整数NN,返回N皇后的摆法数。
示例1
输入
1
返回值
1
示例2
输入
8
返回值
92
show the code as follow:
package math;
import org.junit.Test;
/**
* N皇后问题的实现
* @author jsyuger
* 用一个一维数组arr[i],数组下标i表示皇后放置的行号,arr[i]的值表示皇后放置的列号
* 通过不断地探索与回溯,采用递归的思维,试验出N*N的棋盘是否满足N皇后的布局
*/
public class Nqueen {
private int result = 0 ; //所有可能的布局结果的总数
@Test
public void test() {
int queen[] = new int[9]; //9皇后测试
traceback(queen, 0 , 9); //从第0行开始摆放
System.out.println("result is " + result);
}
/**
* 探索与回溯
* @param array 放置皇后的数组
* @param j 放置皇后的行号
* @param n 总的棋盘行(列)数
* @return
*/
public int traceback(int array[] , int j ,int n) {
if(j>=n) result++; // 已经放到最后一行,且最后一行放完满足条件
else {
for(int k = 0; k<n; k++) {
array[j] = k; //皇后放置的列位置,挨个传递进去校验
if(place(array , j)) {
traceback(array ,j+1, n); //校验通过则开始放下一行,递归思想
}
}
}
return result;
}
/**
* 满足N皇后位置放置的约束判断
* @param arr 放置皇后的数组
* @param a 最新放置的皇后的行号
* @return
*/
public boolean place(int arr[] , int a) {
//每放置一个皇后,都与前面所有的皇后进行位置校验
for(int i=0;i<a;i++) {
if((arr[i]==arr[a]) || (Math.abs(a-i) == Math.abs(arr[i]-arr[a])))
return false;
}
return true;
}
}
这道算法题十分消耗CPU,14个皇后的时候已经需要好几秒,15个皇后我的辣鸡PC已经在响了,时间消耗几乎是指数级增长。数据比较大的时候,网络上大神们都提倡先进行打表操作,即先进行必要的耗性能计算再完成整个程序的设计。