8皇后问题

数学家高斯研究过组合数学中的八皇后问题,在8*8的棋盘上放置8个皇后,保证她们互不攻击,请问有多少种解法。


8皇后问题_第1张图片
一个可行解

高斯的答案是76,可惜算错了,这说明这个问题是很难发现规律,所以最宜使用暴力算法,除非你能超越高斯发现巧算的规律。

即使是暴力算法,也有笨的算法和聪明的算法,前者完全枚举,而后者部分枚举。

这个问题可以分成8个步骤,每个步骤在每行放入一个皇后,当然放入前要检查是否和前面的皇后发生攻击。正因为每个步骤的工作非常相似,所以使用递归枚举。如果当前步骤没有合法选择,那么会返回上一级递归调用,所以递归枚举算法也叫回溯法。正是回溯(backtrace)的存在,所以避免了完全枚举(给解答树减枝)。

编程之前需要选择合适的数据结构,怎样存储前面的皇后的位置?用一个二维数组?其实只要用一维数组就够了,因为这些皇后不可能同列。

那怎样判断皇后是否在对角线上呢?这就需要一些数学知识了。从如果是主对角线方向上,那么x-y的值会相等;如果是从对角线上,x+y的值会相等。

static int cnt = 0;
void search(int cur, int[] queens) {
    if (cur == queens.length) {
        System.out.println(Arrays.toString(queens));
        cnt++;
        return;
    }
    // i 表示 列
    for (int i = 0; i < queens.length; i++) {
        // 坐标 cur, i
        // 坐标 j, queens[j]
       boolean ok = true;
        for (int j = 0; j < cur; j++) {
            if (queens[j] == i ||  cur - i == j - queens[j] ||  cur + i == j + queens[j]) {
                ok = false;
                break;
            }
        }
        if (ok) {
            queens[cur] = i;
            search(cur + 1, queens);
        }
    }
}

如果把检查的那段代码抽象成方法,那么会更加可读。

递归枚举算法有一个极易出错的点,就是如果存在全局变量,需要考虑当前的递归分支对其他递归分支的影响。

你可能感兴趣的:(8皇后问题)