在学习数据结构的时候,看到了一道八皇后的问题。写完后,再去网上查看发现原来这个问题有这么多的优化解法,相比之下相形见绌。但我还是记录下来,有兴趣的小伙伴可以看看。
先大致说下我的思路
创建一个初始化值为0的8x8的数组,0代表无皇后且不在其他皇后的攻击范围,-1代表皇后的位置,>0的整数代表格子在皇后的攻击范围。例如某个格子的数字为3说明该格子在3个皇后的攻击范围。
当遍历到二维数组的某个位置值为0,说明该位置安全,即可放置皇后,把皇后的位置设置为-1,并把该位置的竖,横,斜方向的格子全都+1,然后就直接跳到下一行继续查找合适的位置放置下一个皇后。假如该行查找完后并没有合适的位置,这时候就会回溯上一行,先把上一行当前皇后位置设置为0,并把该位置的竖,横,斜方向的格子全都-1,继续往右边格子遍历…以此类推。
下面是代码,最后求出8皇后一共有92种可能(没排除对称)
同样适用于求N皇后。
import java.util.ArrayList;
import java.util.List;
/**
* 八皇后问题(N皇后问题)
*/
public class EightQueens {
private static List<int[][]> list = new ArrayList<int[][]>();
private static int[][] checkerboard;
/** N代表皇后个数 */
private static int N;
public void judge(int i, int j) {
if(checkerboard[i][j] != 0) {
checkerboard[i][j]++;
} else {
checkerboard[i][j] = 1;
}
}
/**
* 把原来该格子所在的皇后标识和攻击范围去除。
*/
public void toBack(int i, int m) {
for(int j = 0; j < N; j++) {
checkerboard[m][j]--;
checkerboard[j][i]--;
}
for(int x = i, y = m; x >=0 && y < N; x--, y++) {
checkerboard[y][x]--;
}
for(int x = i, y = m; x < N && y < N; x++, y++) {
checkerboard[y][x]--;
}
for(int x = i, y = m; x < N && y >= 0; x++, y--) {
checkerboard[y][x]--;
}
for(int x = i, y = m; x >= 0 && y >= 0; x--, y--) {
checkerboard[y][x]--;
}
checkerboard[m][i] = 0;
}
public boolean search(int m) {
for(int i = 0; i < N; i++) {
if(checkerboard[m][i] == 0) {
//在二位数组中把攻击范围和皇后位置加上标识
for(int j = 0; j < N; j++) {
judge(m, j);
judge(j, i);
}
for(int x = i, y = m; x >=0 && y < N; x--, y++) {
judge(y, x);
}
for(int x = i, y = m; x < N && y < N; x++, y++) {
judge(y, x);
}
for(int x = i, y = m; x < N && y >= 0; x++, y--) {
judge(y, x);
}
for(int x = i, y = m; x >= 0 && y >= 0; x--, y--) {
judge(y, x);
}
checkerboard[m][i] = -1;
//当m>=N说明一种情况完成,继续判断下一种情况
if(++m >= N) {
//输出该可能的皇后位置排列
/*
System.out.println("num: " + list.size() + "--------------------------");
for(int x = 0; x < N; x++) {
for(int y = 0; y < N; y++) {
if(checkerboard[x][y] < 0) {
System.out.print("1 ");
} else {
System.out.print("0 ");
}
}
System.out.println();
}
*/
list.add(checkerboard);
//把当前位置的皇后标识和攻击范围去除
toBack(i, --m);
//继续下一格
continue;
}
//递归往下层走
if(!search(m)) {
//回溯
toBack(i, --m);
} else {
return true;
}
}
}
return false;
}
public static void main(String[] args) {
EightQueens eightQueens = new EightQueens();
for(int i = 1; i <= 14; i++) {
N = i;
checkerboard = new int[i][i];
eightQueens.search(0);
System.out.println(i + "皇后一共有" + list.size() + "种可能");
list.clear();
}
}
}
还有更好的解法
运用一维数组解决N皇后问题
使用回溯法和子集树(降维法)解决N皇后问题