52. N-Queens II

来源:互联网 发布:深圳淘宝化妆品销售 编辑:程序博客网 时间:2024/04/30 09:40

题目:N-Queens II

原题链接:https://leetcode.com/problems/n-queens-ii/
Follow up for N-Queens problem.
Now, instead outputting board configurations, return the total number of distinct solutions.
对于任意的规模n,给出n皇后问题的所有解的数目。

n皇后问题,简单来说就是,在一张n * n的棋盘上,任意放置 n 个位置的皇后,使得任意两个皇后不在同一行、不在同一列、不在同一对角线(包括正负对角线)上,求满足条件的所有解的情况。

这是回溯法的经典问题,我们所要做的就是穷举所有的情况,然后根据不同的情形来回溯。

首先,如何判断两个皇后的位置是不是满足要求的,这里,我们用一维数组a[ i ]来存储皇后的位置,其中数组下标 i 代表是在第 i 行,元素的值代表第a[ i ]列,由于下标唯一,所以不在同一行是肯定满足的,不在同一列通过可以比较a[ i ]和a[ j ]的数值来判断,剩下来的就是如何判断是不是在同一个对角线了,如果在同一个对角线上,可以想象成它们是一个正方形的对角顶点,由于正方形的四边长相等,所以我们只要判断这两个皇后位置的行列之差绝对值是不是相等就可以了,即a[ i ] - a[ j ] == i - j || a[ j ] - a[ i ] == i - j。
这样在假设前面i - 1行位置都已经满足要求的情况下,只要拿前面每一行都和 i 行来比较一下,就可以得出当前位置是不是冲突了。这部分代码如下:

bool isConflict(int* a, int n) {        bool flag = false;        for(int i = 0; i < n; ++i) {            if(a[n] == a[i] || (a[n] - a[i]) == (n - i) || (a[i] - a[n]) == (n - i)) {                flag = true;                break;            }        }        return flag;    }

接下来就是如何求解的过程(假设问题的规模是n,下标是从0到n - 1):
求解的整体思想是在当前 i - 1 行已经不冲突的情况下开始寻找下一行(第 i 行)皇后的合适位置,从第0列到第n - 1列开始寻找,如果在第 j 列不冲突,那么就进行第 i + 1行皇后的尝试,如果当在某一行的时候一直扫描到第n - 1列都没有合适的位置的时候,这个时候就需要回溯,将当前扫描行的列数复位至0,然后回溯到上一行,将上一行的皇后位置再往右移动一列(即列数增加1),然后重新从这一行开始判断,就这样不断的判断不断的回溯,当第n - 1行的不冲突位置已经找到的时候,就已经找到一种符合要求的解法了,然后列数再加一进行判断,以此往复,当回溯到第0行,并且列数已经到达最右(即a[ 0 ] == n - 1)时,此时已经没有办法再往右移动了,整个求解过程结束。
具体代码如下:

class Solution {public:    // 判断是否与前 n - 1 行冲突    bool isConflict(int* a, int n) {        bool flag = false;        for(int i = 0; i < n; ++i) {            if(a[n] == a[i] || (a[n] - a[i]) == (n - i) || (a[i] - a[n]) == (n - i)) {                flag = true;                break;            }        }        return flag;    }    int totalNQueens(int n) {        int count = 0;        int a[n] = {0}; // 初始置为0        int row = 0;        while(1) {            if(row == 0 && a[row] >= n) break; // 已经无法再回溯            else if(row >= n) { // 找到一个符合要求的解                count++;                row--;                a[row]++;                continue;            }else if(a[row] >= n) { // 当前行已经穷举结束,回溯到上一行                a[row] = 0;                row--;                a[row]++;                continue;            }            if(isConflict(a,row)) { // 冲突,则穷举下一列                a[row]++;            } else { // 不冲突,开始下一行的穷举                row++;            }        }        return count;    }};
0 0
原创粉丝点击