背景
八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上
八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为 n×n ,而皇后个数也变成n 。当且仅当n = 1或n ≥ 4时问题有解。
盲目的枚举算法
通过N重循环,枚举满足约束条件的解(八重循环代码好多,这里进行四重循环),找到四个皇后的所有可能位置,然后再整个棋盘里判断这四个皇后是否会直接吃掉彼此,程序思想比较简单。
function check1(arr, n) {
for(var i = 0; i < n; i++) {
for(var j = i + 1; j < n; j++) {
if((arr[i] == arr[j]) || Math.abs(arr[i] - arr[j]) == j - i) {
return false;
}
}
}
return true;
}
function queen1() {
var arr = [];
for(arr[0] = 1; arr[0] <= 4; arr[0]++) {
for(arr[1] = 1; arr[1] <= 4; arr[1]++) {
for(arr[2] = 1; arr[2] <= 4; arr[2]++) {
for(arr[3] = 1; arr[3] <= 4; arr[3]++) {
if(!check1(arr, 4)) {
continue;
} else {
console.log(arr);
}
}
}
}
}
}
queen1();
//[ 2, 4, 1, 3 ]
//[ 3, 1, 4, 2 ]
回溯法
『走不通,就回头』,在适当节点判断是否符合,不符合就不再进行这条支路上的探索。
function check2(arr, n) {
for(var i = 0; i <= n - 1; i++) {
if((Math.abs(arr[i] - arr[n]) == n - i) || (arr[i] == arr[n])) {
return false;
}
}
return true;
}
function queen2() {
var arr = [];
for(arr[0] = 1; arr[0] <= 4; arr[0]++) {
for(arr[1] = 1; arr[1] <= 4; arr[1]++) {
if(!check2(arr, 1)) continue; //摆两个皇后产生冲突的情况
for(arr[2] = 1; arr[2] <= 4; arr[2]++) {
if(!check2(arr, 2)) continue; //摆三个皇后产生冲突的情况
for(arr[3] = 1; arr[3] <= 4; arr[3]++) {
if(!check2(arr, 3)) {
continue;
} else {
console.log(arr);
}
}
}
}
}
}
queen2();
//[ 2, 4, 1, 3 ]
//[ 3, 1, 4, 2 ]
非递归回溯法
function check2(arr, n) {
for (var i = 0; i < n; i++) {
if ((Math.abs(arr[i] - arr[n]) === n - i) || (arr[i] == arr[n])) return false;
}
return true;
}
function backdate(n) {
let arr = [];
let k = 1;// 第n个皇后
arr[0] = 0;
while (k > 0) {
arr[k - 1] = arr[k - 1] + 1;
while ((arr[k - 1] <= n) && (!check2(arr, k - 1))) {
arr[k - 1]++;
}
// 这个皇后满足约束条件,进行下一步判断
if (arr[k - 1] <= n) {
if (k === n) {
console.log(arr);
} else {
k++;// 下一个皇后
arr[k - 1] = 0;
}
} else {
k--;//回溯,上一个皇后
}
}
}
backdate(4);
递归回溯法
function check2(arr, n) {
for (var i = 0; i < n; i++) {
if ((Math.abs(arr[i] - arr[n]) === n - i) || (arr[i] == arr[n])) return false;
}
return true;
}
var arr = [], n = 4;
function backtrack(k) {
if(k > n) {
console.log(arr);
} else {
for(var i = 1;i <= n; i++) {
arr[k-1] = i;
if(check2(arr, k-1)) {
backtrack(k + 1);
}
}
}
}
backtrack(1);