n-queens

N-Queens

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

Given an integer n, return all distinct solutions to the n-queens puzzle.

Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.

For example,
There exist two distinct solutions to the 4-queens puzzle:

[
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

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

 

这题和Sudoku Solver是一个套路,回溯法尝试所有可能性,将可行解的保存起来。可以对比着看。

由于这里路径尝试本质上是有序的,即1~9逐个尝试,因此无需额外设置状态位记录已经尝试过的方向。

我们先用vector<int>来存放可行解,下标代表行号,元素代表列号。

因此上图中Solution 1用vector<int>表示就是[1,3,0,2]

解题流程就是在下一行中尝试列数(0~n-1),如果可行则递归下去,如果不可行则弹出继续尝试下一列。

代码中加入了大量注释,还是很好理解的。

复制代码
class Solution 
{
public:
    vector<vector<string> > solveNQueens(int n) 
    {
        vector<vector<int> > result;    //全局变量
        vector<int> cur;                //递归栈中的变量
        solve(result, cur, n);            //符合条件的cur加入result
        return transfer(result, n);        //vector<int>转为vector<string>
    }

    void solve(vector<vector<int> > &result, vector<int> cur, int n)
    {
        if(cur.size() == n)
        {//找到解
            result.push_back(cur);
        }
        else
        {
            for(int i = 0; i < n; i ++)
            {//尝试所有可能
                cur.push_back(i);
                if(isValid(cur))
                {//可行则递归下去
                    solve(result, cur, n);
                }
                cur.pop_back();
            }
        }
    }

    vector<vector<string> > transfer(vector<vector<int> > &result, int n)
    {
        vector<vector<string> > ret;
        for(vector<vector<int> >::size_type st1 = 0; st1 < result.size(); st1 ++)
        {//第st1个解
            vector<string> cur(n, string(n,'.'));
            for(vector<int>::size_type st2 = 0; st2 < n; st2 ++)
            {//第st2行
                cur[st2][result[st1][st2]] = 'Q';
            }
            ret.push_back(cur);
        }
        return ret;
    }

    bool isValid(vector<int> &cur)
    {//针对新加点进行验证
        int sz = cur.size();
        int row = sz-1;            //新加点的行数sz-1
        int col = cur[sz-1];    //列数cur[sz-1]
        for(vector<int>::size_type st = 0; st < sz-1; st ++)
        {    //验证同列错误(由于数组下标不同,同行错误不存在)
            if(col == cur[st])
                return false;
            //验证同对角线错误
            if(abs(row-st)==abs(col-cur[st]))
                return false;
        }
        return true;
    }
};
复制代码

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值