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.."]
]

算法1

这种棋盘类的题目一般是回溯法, 依次放置每行的皇后。在放置的时候,要保持当前的状态为合法,即当前放置位置的同一行、同一列、两条对角线上都不存在皇后。

class Solution {
private:
vector<vector<string> > res;
public:
vector<vector<string> > solveNQueens(int n) {
vector<string>cur(n, string(n,'.'));
helper(cur, );
return res;
}
void helper(vector<string> &cur, int row)
{
if(row == cur.size())
{
res.push_back(cur);
return;
}
for(int col = ; col < cur.size(); col++)
if(isValid(cur, row, col))
{
cur[row][col] = 'Q';
helper(cur, row+);
cur[row][col] = '.';
}
} //判断在cur[row][col]位置放一个皇后,是否是合法的状态
//已经保证了每行一个皇后,只需要判断列是否合法以及对角线是否合法。
bool isValid(vector<string> &cur, int row, int col)
{
//列
for(int i = ; i < row; i++)
if(cur[i][col] == 'Q')return false;
//右对角线(只需要判断对角线上半部分,因为后面的行还没有开始放置)
for(int i = row-, j=col-; i >= && j >= ; i--,j--)
if(cur[i][j] == 'Q')return false;
//左对角线(只需要判断对角线上半部分,因为后面的行还没有开始放置)
for(int i = row-, j=col+; i >= && j < cur.size(); i--,j++)
if(cur[i][j] == 'Q')return false;
return true;
}
};

算法2

上述判断状态是否合法的函数还是略复杂,其实只需要用一个一位数组来存放当前皇后的状态。假设数组为int state[n], state[i]表示第 i 行皇后所在的列。那么在新的一行 k 放置一个皇后后:

  • 判断列是否冲突,只需要看state数组中state[0…k-1] 是否有和state[k]相等;
  • 判断对角线是否冲突:如果两个皇后在同一对角线,那么|row1-row2| = |column1 - column2|,(row1,column1),(row2,column2)分别为冲突的两个皇后的位置
    class Solution {
    private:
    vector<vector<string> > res;
    public:
    vector<vector<string> > solveNQueens(int n) {
    vector<int> state(n, -);
    helper(state, );
    return res;
    }
    void helper(vector<int> &state, int row)
    {//放置第row行的皇后
    int n = state.size();
    if(row == n)
    {
    vector<string>tmpres(n, string(n,'.'));
    for(int i = ; i < n; i++)
    tmpres[i][state[i]] = 'Q';
    res.push_back(tmpres);
    return;
    }
    for(int col = ; col < n; col++)
    if(isValid(state, row, col))
    {
    state[row] = col;
    helper(state, row+);
    state[row] = -;;
    }
    } //判断在row行col列位置放一个皇后,是否是合法的状态
    //已经保证了每行一个皇后,只需要判断列是否合法以及对角线是否合法。
    bool isValid(vector<int> &state, int row, int col)
    {
    for(int i = ; i < row; i++)//只需要判断row前面的行,因为后面的行还没有放置
    if(state[i] == col || abs(row - i) == abs(col - state[i]))
    return false;
    return true;
    }
    };

    算法3:(算法2的非递归版)

    class Solution {
    private:
    vector<vector<string> > res;
    public:
    vector<vector<string> > solveNQueens(int n) {
    vector<int> state(n, -);
    for(int row = , col; ;)
    {
    for(col = state[row] + ; col < n; col++)//从上一次放置的位置后面开始放置
    {
    if(isValid(state, row, col))
    {
    state[row] = col;
    if(row == n-)//找到了一个解,继续试探下一列
    {
    vector<string>tmpres(n, string(n,'.'));
    for(int i = ; i < n; i++)
    tmpres[i][state[i]] = 'Q';
    res.push_back(tmpres);
    }
    else {row++; break;}//当前状态合法,去放置下一行的皇后
    }
    }
    if(col == n)//当前行的所有位置都尝试过,回溯到上一行
    {
    if(row == )break;//所有状态尝试完毕,退出
    state[row] = -;//回溯前清除当前行的状态
    row--;
    }
    }
    return res;
    } //判断在row行col列位置放一个皇后,是否是合法的状态
    //已经保证了每行一个皇后,只需要判断列是否合法以及对角线是否合法。
    bool isValid(vector<int> &state, int row, int col)
    {
    for(int i = ; i < row; i++)//只需要判断row前面的行,因为后面的行还没有放置
    if(state[i] == col || abs(row - i) == abs(col - state[i]))
    return false;
    return true;
    }
    };

    算法4(解释在后面)这应该是最高效的算法了

    class Solution {
    private:
    vector<vector<string> > res;
    int upperlim;
    public:
    vector<vector<string> > solveNQueens(int n) {
    upperlim = ( << n) - ;//低n位全部置1
    vector<string> cur(n, string(n, '.'));
    helper(,,,cur,);
    return res;
    } void helper(const int row, const int ld, const int rd, vector<string>&cur, const int index)
    {
    int pos, p;
    if ( row != upperlim )
    {
    pos = upperlim & (~(row | ld | rd ));//pos中二进制为1的位,表示可以在当前行的对应列放皇后
    //和upperlim与运算,主要是ld在上一层是通过左移位得到的,它的高位可能有无效的1存在,这样会清除ld高位无效的1
    while ( pos )
    {
    p = pos & (~pos + );//获取pos最右边的1,例如pos = 010110,则p = 000010
    pos = pos - p;//pos最右边的1清0
    setQueen(cur, index, p, 'Q');//在当前行,p中1对应的列放置皇后
    helper(row | p, (ld | p) << , (rd | p) >> , cur, index+);//设置下一行
    setQueen(cur, index, p, '.');
    }
    }
    else//找到一个解
    res.push_back(cur);
    } //第row行,第loc1(p)列的位置放置一个queen或者清空queen,loc1(p)表示p中二进制1的位置
    void setQueen(vector<string>&cur, const int row, int p, char val)
    {
    int col = ;
    while(!(p & ))
    {
    p >>= ;
    col++;
    }
    cur[row][col] = val;
    }
    };

    这个算法主要参考博客N皇后问题的两个最高效的算法,主要看helper函数,参数row、ld、rd分别表示在列和两个对角线方向的限制条件下,当前行的哪些地方不能放置皇后。如下图

    前三行放置了皇后,他们对第3行(行从0开始)的影响如下:                               本文地址

    (1)列限制条件下,第3行的0、2、4列(紫色线和第3行的交点)不能放皇后,因此row = 101010

    (2)左对角线限制条件下,第3行的0、3列(蓝色线和第3行的交点)不能放皇后,因此ld = 100100

    (3)右对角线限制条件下,第3行的3、4、5列(绿色线和第3行的交点)不能放皇后,因此rd = 000111

    ~(row | ld | rd) = 010000,即第三行只有第1列能放置皇后。

    在3行1列这个位置放上皇后,row,ld,rd对下一行的影响为:

    row的第一位置1,变为111010

    ld的第一位置1,并且向左移1位(因为左对角线对行的影响是依次向左倾斜的),变为101000

    rd的第一位置1,并且向右移1位(因为右对角线对行的影响是依次向右倾斜的),变为001011

    第4行状态如下图


    N-Queens II

    Follow up for N-Queens problem.

    Now, instead outputting board configurations, return the total number of distinct solutions.

    这一题就是上一题的简化版了,我们只针对上面的算法2来求解这一题

    class Solution {
    private:
    int res;
    public:
    int totalNQueens(int n) {
    vector<int> state(n, -);
    res = ;
    helper(state, );
    return res;
    }
    void helper(vector<int> &state, int row)
    {//放置第row行的皇后
    int n = state.size();
    if(row == n)
    {
    res++;
    return;
    }
    for(int col = ; col < n; col++)
    if(isValid(state, row, col))
    {
    state[row] = col;
    helper(state, row+);
    state[row] = -;;
    }
    } //判断在row行col列位置放一个皇后,是否是合法的状态
    //已经保证了每行一个皇后,只需要判断列是否合法以及对角线是否合法。
    bool isValid(vector<int> &state, int row, int col)
    {
    for(int i = ; i < row; i++)//只需要判断row前面的行,因为后面的行还没有放置
    if(state[i] == col || abs(row - i) == abs(col - state[i]))
    return false;
    return true;
    } };

    转自:http://www.cnblogs.com/TenosDoIt/p/3801621.html

N-Queens I II(n皇后问题)(转)的更多相关文章

  1. lintcode 中等题:N Queens II N皇后问题 II

    题目: N皇后问题 II 根据n皇后问题,现在返回n皇后不同的解决方案的数量而不是具体的放置布局. 样例 比如n=4,存在2种解决方案 解题: 和上一题差不多,这里只是求数量,这个题目定义全局变量,递 ...

  2. [Leetcode] n queens ii n皇后问题

    Follow up for N-Queens problem. Now, instead outputting board configurations, return the total numbe ...

  3. [LeetCode] N-Queens II N皇后问题之二

    Follow up for N-Queens problem. Now, instead outputting board configurations, return the total numbe ...

  4. [leetcode]52. N-Queens II N皇后

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

  5. [LeetCode] 52. N-Queens II N皇后问题之二

    The n-queens puzzle is the problem of placing nqueens on an n×n chessboard such that no two queens a ...

  6. [LeetCode] 52. N-Queens II N皇后问题 II

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

  7. 52. N-Queens II N皇后II

    网址:https://leetcode.com/problems/n-queens-ii/ 方法1:按照逻辑思路,通过回溯法解决问题.速度较慢! class Solution { public: vo ...

  8. [CareerCup] 9.9 Eight Queens 八皇后问题

    9.9 Write an algorithm to print all ways of arranging eight queens on an 8x8 chess board so that non ...

  9. Java实现 LeetCode 52 N皇后 II

    52. N皇后 II n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击. 上图为 8 皇后问题的一种解法. 给定一个整数 n,返回 n 皇后不同的解决方案 ...

  10. Java与算法之(6) - 八皇后问题

    在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法. (文字和图片来自百度百科) 如果动手来摆放皇后,可以用这样一种思路:在最左侧 ...

随机推荐

  1. 明星伙伴第一至八季/全集Entourage迅雷下载

    英文译名Entourage,第1-8季(04-2011)HBO.本季看点:<明星伙伴>这是一部HBO原创系列喜剧,讲述年少成名的男主人公文森 .蔡斯和他的三个少年时纽约皇后区的朋友一道冒险 ...

  2. 美国恐怖故事第一季/全集American Horror Story 1全迅雷下载

    第一季 American Horror Story Season 1 (2011)看点:心理治疗师Ben(迪伦·麦克德莫特 Dylan McDermott 饰)因与女学生有染被妻子Vivien(康妮· ...

  3. 纸牌屋第一季/全集House of Cards迅雷下载

    纸牌屋 第一季 House of Cards Season 1 (2013) 本季看点:经过数轮激烈角逐,新一届美国总统加勒特·沃克(迈克·吉尔 Michael Gill 饰)诞生,自称水管工的众议院 ...

  4. Java中的线程实现

    线程实现有两种方法: 1.写一个类来继承Thread类,然后复写run()方法. public class HelloThread extends Thread { public void run() ...

  5. SVG渲染顺序及z轴显示问题(zIndex)

    SVG是严格按照定义元素的顺序来渲染的,这个与HTML靠z-index值来控制分层不一样. 在SVG中,写在前面的元素先被渲染,写在后面的元素后被渲染.后渲染的元素会覆盖前面的元素,虽然有时候受透明度 ...

  6. [转]用 jQuery 实现页面滚动(Scroll)效果的完美方法

    转自: http://zww.me/archives/25144 很多博主都写过/转载过用 jQuery 实现页面滚动(Scroll)效果的方法,但目前搜来的方法大都在 Opera 下有个小 Bug: ...

  7. 机器学习、NLP、Python和Math最好的150余个教程(建议收藏)

    编辑 | MingMing 尽管机器学习的历史可以追溯到1959年,但目前,这个领域正以前所未有的速度发展.最近,我一直在网上寻找关于机器学习和NLP各方面的好资源,为了帮助到和我有相同需求的人,我整 ...

  8. 必须记住的 30 类 CSS 选择器

    大概大家读知道`id`,`class`以及`descendant`选择器,并且整体都在使用它们,那么你正在错误拥有更大级别的灵活性的选择方式.这篇文章里面提到的大部分选择器都是在CSS3标准下的,所以 ...

  9. python3 IEDriver抓取时报数据

    最近做了测试抓取XX时报的数据,由于需要事先登录,并且有验证码,关于验证码解决有两个途径:一是利用打码平台,其原理是把验证码的图片上传发送给打码平台, 然后返回其验证码.二就是自己研究验证码技术问题. ...

  10. Java信号量Semaphore

    Semaphore Semaphore分为单值和多值两种,前者只能被一个线程获得,后者可以被若干个线程获得. Semaphore实现的功能就类似厕所有5个坑,假如有10个人要上厕所,那么同时只能有多少 ...