LeetCode OJ 之 N-Queens(N皇后)

题目:

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.

N皇后问题是在一个n x n 的棋盘上放置N个皇后,使得每个皇后不同行、不同列也不能在同一条斜线上。

给定一个整数n,返回所有不同的可能性。每个结果包含不同的设置,放置Q和 . 分别代表一个皇后和空格。

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

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

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

思路:

1、这里可以用数组vector<int> q(n,0),q[i]表示第 i 行的queen放在 q[i] 列,这样就转化成求0~n-1总共 n 个数的全排列,全排列可以参考:http://blog.csdn.net/u012243115/article/details/42965749 。然后对这n! 个全排列进行筛选,这个全排列保证了棋盘图的每个皇后的行列不同,还要判断每个皇后的位置不在一条斜线上,详情见代码。

2、依次放置每行的皇后。在放置的时候,要保持当前的状态为合法,即与上面行的皇后不冲突,即当前放置位置的同一行、同一列、同一斜线线上都不存在皇后。

3、结合上面两种方法。

代码1:

class Solution {
public:
    vector<vector<string> > solveNQueens(int n)
    {
        vector<vector<string> > result;//保存结果
        vector<int> q(n,0);//q[i]表示棋盘上第i行的'Q'位于q[i]列,下面的for循环初始化使得每个'Q'位于不同行不同列
        for(int i = 0 ; i < n ; i++)    //初始化q
        {
            q[i] = i;
        }
        DFS(n,0,q,result);//调用DFS构造棋盘图
        return result;
    }
    void DFS(int n , int start , vector<int> &q , vector<vector<string> > &result)
    {
        if(start == n)
        {
            //筛选全排列
            for(int i = 0 ; i < n ; i++)
            {
                for(int j = i + 1 ; j < n ; j++)
                {
                    if((j-i) == abs(q[j]-q[i])) //如果两个皇后在一条斜线上,则此种排列不符合条件,直接返回
                    {
                        return;
                    }
                }
            }
            //如果没有被筛选掉,则构造棋盘图
            vector<string> cur(n,string(n,'.'));//先构造一个全部为'.'的图,然后再设置皇后的位置
            for(int i = 0 ; i < n ; i++)
            {
                cur[i][q[i]] = 'Q';//把第i行,第q[i]列的元素设置为皇后
            }
            result.push_back(cur);
            return;
        }
        for(int i = start ; i < n ; i++)
        {
            swap(q[i],q[start]);
            DFS(n,start+1,q,result);//递归求全排列
            swap(q[i],q[start]);
        }
    }
};

代码2:

class Solution {
private:
    vector<vector<string> > result;
public:
    vector<vector<string> > solveNQueens(int n) 
    {
        vector<string> cur(n, string(n,'.'));
        DFS(cur, 0);
        return result;
    }
    void DFS(vector<string> &cur, int row)
    {
        if(row == cur.size())
        {
            result.push_back(cur);
            return;
        }
        for(int col = 0; col < cur.size(); col++)
        {
            if(isValid(cur, row, col))
            {
                cur[row][col] = 'Q';//在当前位置放置皇后之前检查是否与上面的皇后冲突,不冲突后才能放置
                DFS(cur, row+1);//递归调用下一行
                cur[row][col] = '.';//恢复当前位置
            }
        }
    }
    //判断在cur[row][col]位置放一个皇后,是否是合法的位置
    //已经保证了每行一个皇后,只需要判断列是否合法以及对角线是否合法。
    bool isValid(vector<string> &cur, int row, int col)
    {
        //列
        for(int i = 0; i < row; i++)
        {
            if(cur[i][col] == 'Q')
                return false;
        }
        //左上角对角线(只需要判断对角线上半部分,因为后面的行还没有开始放置)
        for(int i = row-1, j=col-1; i >= 0 && j >= 0; i--,j--)
        {
            if(cur[i][j] == 'Q')
                return false;
        }
        //右上角对角线(只需要判断对角线上半部分,因为后面的行还没有开始放置)
        for(int i = row-1, j=col+1; i >= 0 && j < cur.size(); i--,j++)
        {
            if(cur[i][j] == 'Q')
                return false;
        }
        return true;
    }
};

代码3:

class Solution {
private:
    vector<vector<string> > result;
public:
    vector<vector<string> > solveNQueens(int n) 
    {
        vector<int> q(n,-1);
        DFS(n,q, 0);
        return result;
    }
    void DFS(int n , vector<int> &q, int row)
    {
        if(row == n)
        {
            vector<string> cur(n,string(n,'.'));
            for(int i = 0 ; i < n ; i++)
            {
                cur[i][q[i]] = 'Q';
            }
            result.push_back(cur);
            return;
        }
        for(int col = 0; col < n; col++)
        {
            if(isValid(q, row, col))
            {
                q[row] = col;//在当前位置放置皇后之前检查是否与上面的皇后冲突,不冲突后才能放置
                DFS(n,q,row+1);//递归调用下一行
                q[row] = -1;//恢复当前位置
            }
        }
    }
    bool isValid(vector<int> q, int row, int col)
    {
        for(int i = 0 ; i < row ; i++)
        {
            if(q[i] == col || (row - i) == abs(col - q[i]))
                return false;
        }
        return true;
    }
};



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值