【lintcode】N皇后问题

本文介绍了一种使用回溯法解决N皇后问题的方法,并提供了一个详细的C++实现案例。通过一维数组记录每行皇后的坐标,判断是否冲突并递归求解所有可行方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

n皇后问题是将n个皇后放置在n*n的棋盘上,皇后彼此之间不能相互攻击。
给定一个整数n,返回所有不同的n皇后问题的解决方案。
每个解决方案包含一个明确的n皇后放置布局,其中“Q”和“.”分别表示一个女王和一个空位置。

样例
对于4皇后问题存在两种解决的方案:
[".Q..", // Solution 1

 "...Q",

 "Q...",

  "..Q."],

 ["..Q.", // Solution 2

 "Q...",

  "...Q",

   ".Q.."]

思路:

  • 国际象棋中皇后可以攻击同行同列以及同一斜线上的棋子,所以要以此来判断在一个棋盘格上能否放置一个皇后。我们使用一个长度为n的一维数组Queens来存储每一行的皇后的位置(-1表示没有皇后)。对于位置(r, c),只需判断Queens[i] >= 0 && (Queens[i] == c || abs(r-i) == abs(c-Queens[i])) ,若为真表示有冲突,不可放置。
  • 求解过程使用回溯法,(r,c)表示当前位置 对于该位置有如下几种情况:
    1.r == n-1
     a.  c == n-1(即行尾), 如果有解,则记录这个解,然后回溯到上一行的皇后之后的位置(同时删去关于该皇后的记录);否则直接回溯到上一行
     b. 未到行尾,如果有解,则记录这个解,然后清除该行的记录,最后将c加1,移动到下一个位置;否则直接移动到下一个位置
     
    2.r < n-1(即未到最后一行)
     a. c < n-1,即没有到行尾 如果可以放置皇后则记录相应的位置,然后令 r = r + 1, c = 0 ,移动到下一行; 否则将c加1,移动到下一个位置
     b.c == n-1,即到达行尾 如果可以放置皇后,则记录,然后移动到下一行;否则,则回溯到上一行的皇后所在位置的后一个位置

    3.在回溯的过程中可能会出现c >= n的情况,这时候如果 r == 0,则函数直接返回;否则回溯到上一行

代码

第一次写的题解中核心函数solve太过复杂,下面先提前给出一个简化过的solve函数。

    void solve2(int r){
        if(r == n){
            for(int i = 0; i < n; i++)
                result[i][Queens[i]] = 'Q';
            results.push_back(result);

            for(int i = 0; i < n; i++)
                for(int j = 0; j < n; j++)
                    result[i][j] = '.';
        }
        else{
            for(int i = 0; i < n; i++){
                for(int j = r; j < n; j++)
                    Queens[j] = -1;
                if(check(r, i)){
                    Queens[r] = i;
                    solve2(r+1);
                }
            }
        }
    }

完整题解如下


class Solution {
    vector<int> Queens;
    vector<vector<string> > results;
    vector<string> result;
    int n;
public:
    /*
     * @param n: The number of queens
     * @return: All distinct solutions
     */
    vector<vector<string> > solveNQueens(int _n) {
        // write your code here
        n = _n;
        Queens.resize(n, -1);
        result.resize(n);
        for(int i = 0; i < n; i++)
            result[i].resize(n, '.');

        if(n == 1){
            result[0][0] = 'Q';
            results.push_back(result);
            return results;
        }
        else if(n < 4)
            return results;

        solve(0,0);
        return results;
    }

    void solve(int r, int c){
        if(c  >= n)
            if(r == 0)
                return;
            else{
                r--;
                //删去回溯点的解
                result[r][Queens[r]] = '.'; 
                int t = Queens[r];
                Queens[r] = -1;
                solve(r, t+1); //回溯到上一行
                return;
            }
        if(r == n-1){
            for( ; c < n; c++){
                if(check(r,c)){
                    result[r][c] = 'Q';
                    results.push_back(result); //添加新解
                    result[r][c] = '.'; //删去本行的皇后
                }
                if(c == n-1){ 
                    //若已到行尾,则回溯
                    r--;
                    //删去回溯点的解
                    result[r][Queens[r]] = '.'; 
                    int t = Queens[r];
                    Queens[r] = -1;
                    solve(r, t+1); //回溯到上一行
                    return;
                }
            }
        }
        else{
            for( ; c < n; c++){
                if(check(r,c)){
                    result[r][c] = 'Q';
                    Queens[r] = c;
                    r++;
                    solve(r,0);
                    return;
                }
                if(c == n-1){
                    if(r == 0)
                        return; //如果已经回溯到了第一行,则返回
                    else{
                        r--;
                        //删去回溯点的解
                        result[r][Queens[r]] = '.'; 
                        int t = Queens[r];
                        Queens[r] = -1;
                        solve(r, t+1); //回溯到上一行
                        return;
                    }
                }
            }
        }
    }

    int check(int r, int c){
        for(int i = 0; i < Queens.size(); i++)
            if(Queens[i] >= 0 && (Queens[i] == c || abs(r-i) == abs(c-Queens[i])) ) 
                return 0;
        return 1;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值