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

思路I:按行递归,在每个递归过程中按列循环,此时可能会有多种选择,所以使用回溯法。

注意每个小对角线也要check。

class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
if(n==) return result; string str="";
for(int i = ; i< n; i++){ //construct "...."
str += '.';
}
vector<string> item(n,str);
backTracking(n, item, );
return result; } void backTracking(int n, vector<string>& item, int depth){ //depth is the line number
if(depth==n){
result.push_back(item);
return;
} for(int i = ; i < n; i++){ //traverse column
item[depth][i] = 'Q';
if(check(n,item, depth, i)) backTracking(n,item,depth+);
item[depth][i] = '.'; //back track
}
} bool check(int n, vector<string>& item, int i, int j){
int k;
//check line to see if there's repetition
for(k = ; k < n; k++){
if(k==i) continue;
if(item[k][j]=='Q') return false;
} //check column to see if there's repetition
for(k = ; k < n; k++){
if(k==j) continue;
if(item[i][k]=='Q') return false;
} //check upper left
for(k = ; i-k >= && j-k>=; k++){
if(item[i-k][j-k]=='Q') return false;
} //check lower right
for(k = ; i+k <n && j+k<n; k++){
if(item[i+k][j+k]=='Q') return false;
} //check upper right
for(k = ; i-k >= && j+k<n; k++){
if(item[i-k][j+k]=='Q') return false;
} //check lower left
for(k = ; i+k <n && j-k>=; k++){
if(item[i+k][j-k]=='Q') return false;
} return true;
}
private:
vector<vector<string>> result;
};

思路II:对思路I,简化check

首先,对于每一行,不用check,因为在一个for循环中已经用回溯规避了重复。

对于列,我们用一个一维数组标记Q的位置,下标为行号,值为出现Q的列号。

对于对角线的check,check每一列Q所在的(row2,column2) 与当前点(row1, column1)是否满足|row1-row2| = |column1 - column2|,满足表示在一个对角线上。

class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
if(n==) return result; vector<int> flag(n,-); //每行的Q出现在哪列
backTracking(n, flag, );
return result;
} void backTracking(int n, vector<int>& flag, int depth){ //depth is the line number
if(depth==n){
vector<string>item(n, string(n,'.')); //initialize as all '.'
for(int i = ; i < n; i++)
item[i][flag[i]] = 'Q';
result.push_back(item);
return;
} for(int i = ; i < n; i++){ //traverse column
if(check(n,flag, depth, i)) {
flag[depth] = i;
backTracking(n,flag,depth+);
flag[depth] = -; // back track
}
}
} bool check(int n, vector<int>& flag, int i, int j){
for(int k = ; k < i; k++){
if(flag[k] < ) continue;//no Q in this column
if(flag[k]==j) return false;//check columns
if(abs(i-k)==abs(j-flag[k])) return false; //check cross lines
}
return true;
}
private:
vector<vector<string>> result;
};

思路III: 递归调用会有很多函数堆栈处理,参数拷贝,耗时耗内存,所以改用循环。思路还是back track,在没有答案的时候要回溯到上一行的Q位置之后的那个位置。

class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
if(n==) return result; vector<int> flag(n,-);
int i = , j = ;
while(!(i== && j==n)){
if(j==n){ //no valid Q in this line, back track
i--;
j = flag[i]+;
flag[i] = -;
continue;
}
if(i==n){ //find one solution
vector<string>item(n, string(n,'.')); //initialize as all '.'
for(int k = ; k < n; k++)
item[k][flag[k]] = 'Q';
result.push_back(item); //back track
i--;
j = flag[i]+;
flag[i] = -;
continue;
} if(check(n,flag, i, j)) {
flag[i] = j;
i++;
j = ;
}
else{
j++;
}
} return result;
} bool check(int n, vector<int>& flag, int i, int j){
for(int k = ; k < i; k++){
if(flag[k] < ) continue;//no Q in this column
if(flag[k]==j) return false;//check columns
if(abs(i-k)==abs(j-flag[k])) return false; //check cross lines
}
return true;
}
private:
vector<vector<string>> result;
};

思路IV:通过为操作继续简化状态变量,将一维数组简化为整型。通过状态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行状态如下图

class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
if(n==) return result; mask = (<<n) - ; //Bit operation: 低n位置1
vector<string> cur(n, string(n,'.'));
backTracking(, , , cur, );
return result;
} void backTracking(const int row, const int ld, const int rd, vector<string>& cur, int depth){ //depth is the line number
if(row==mask){ //find one solution
result.push_back(cur);
return;
} int pos, p;
pos = mask & (~(row|ld|rd)); //pos置1的位置表示可以放置Q
while(pos){
p = pos & (~pos + );//Bit Operation: 获取pos最右边的1
pos = pos - p; //把pos最右边的1清0
setQueen(cur, depth, p, 'Q');
backTracking(row|p, (ld|p)<<, (rd|p)>>, cur, depth+); //iterate next line
setQueen(cur, depth, p, '.'); //back track
}
} void setQueen(vector<string>& cur, int depth, int p, char val){
int col = ;
while(!(p&)){
p >>= ;
col++;
}
cur[depth][col]=val;
}
private:
vector<vector<string>> result;
int mask;
};

51. N-Queens (Array; Back-Track, Bit)的更多相关文章

  1. How to set the initial value of a select element using AngularJS ng-options & track by

    原文: https://www.gurustop.net/blog/2014/01/28/common-problems-and-solutions-when-using-select-element ...

  2. 嵌入式 使用mp4v2将H264+AAC合成mp4文件

    录制程序要添加新功能:录制CMMB电视节目,我们的板卡发送出来的是RTP流(H264视频和AAC音频),录制程序要做的工作是: (1)接收并解析RTP包,分离出H264和AAC数据流: (2)将H26 ...

  3. window7 触屏操作相关

    一.体系概述 1.Windows Touch Input 和 Gestures消息 Windows Touch消息特性 通过在执行期间的监听和解释来使能.下面的示例展示了Windows7 上消息是怎么 ...

  4. PHP array_multisort() 函数详解 及 二维数组排序(模拟数据表记录按字段排序)

    一.先看最简单的情况. 有两个数组: $arr1 = array(1, 9, 5); $arr2 = array(6, 2, 4); array_multisort($arr1, $arr2); pr ...

  5. NumPy的详细教程

    原文  http://blog.csdn.net/lsjseu/article/details/20359201 主题 NumPy 先决条件 在阅读这个教程之前,你多少需要知道点python.如果你想 ...

  6. Apache Spark源码走读之24 -- Sort-based Shuffle的设计与实现

    欢迎转载,转载请注明出处. 概要 Spark 1.1中对spark core的一个重大改进就是引入了sort-based shuffle处理机制,本文就该处理机制的实现进行初步的分析. Sort-ba ...

  7. C语言解决八皇后问题

    #include <stdio.h> #include <stdlib.h> /* this code is used to cope with the problem of ...

  8. 微信浏览器里location.reload问题

    微信浏览器里location.reload问题会导致有时候post数据丢失.建议不要用此方式,尽量ajax方式获取或不要为了获取新的UI而刷新页面 2015-12-26 00:51:34array ( ...

  9. 使用mp4v2将H264+AAC合成mp4文件

    录制程序要添加新功能:录制CMMB电视节目,我们的板卡发送出来的是RTP流(H264视频和AAC音频),录制程序要做的工作是: (1)接收并解析RTP包,分离出H264和AAC数据流: (2)将H26 ...

  10. PHP数组排列

    一.先看最简单的情况.有两个数组: $arr1 = array(1,9,5);$arr2 = array(6,2,4); array_multisort($arr1,$arr2); print_r($ ...

随机推荐

  1. 常用的sql语句(存储过程语法)

    1.存储过程语法 ①package create or replace package PKG_RPT_WAREHOUSE is -- Author : -- Created : 2018/9/28 ...

  2. http接口测试工具——RESTClient

    摘要: RESTClient是用java Swing编写的基于http协议的接口测试工具,工具比较灵巧,便于做接口的调试,源码在官网上可以下到,感兴趣的可以研究一下 WizTools.org REST ...

  3. SpringBoot学习记(一)第一个SpringBoot Web服务

    工具IDEA 一.构建项目 1.选择Spring Initializr 2.填写项目信息 3.勾选webService 4.勾选Thymeleaf 5.项目建立完成,启动类自动生成 二.写个Contr ...

  4. TCP阻塞模式开发

    在阻塞模式下,在IO操作完成前,执行的操作函数将一直等候而不会立刻返回,该函数所在的进程会阻塞在这里.相反,在非阻塞模式下,套接字函数会立即返回,而不管IO是否完成,该函数所在的线程将继续运行.阻塞模 ...

  5. windows 下,查看并杀死进程

    今天启动我的play framework 服务 提示 could not bind on 9000.还是个error.这让我很不解,昨天还好好的. 怀疑是9000呗某个服务占了,在linux下还挺好办 ...

  6. tomcat启动原理

    2018年04月12日 19:55:22 太极小帅帅 阅读数:282   前言 一直在用Tomcat,但是对其启动原理一直没去研究,这里准备去面试,可能会问道.于是总结了下启动原理.完全凭感觉去揣测, ...

  7. cplexJava源码---计算结果

    public static class CplexStatus implements Serializable { static final long serialVersionUID = -7367 ...

  8. apache伪静态失败,但是phpinfo显示有rewrite的时候考虑的情况

    大家知道除了加载loadmodule后 还需要修改http.conf 使apache支持.htaccess 允许在任何目录中使用“.htaccess”文件,将“AllowOverride”改成“All ...

  9. 0_Simple__simpleStreams

    对比使用单流和多流(4条)情况下数据拷贝,以及数据拷贝加内核调用的效率差别.▶ 源代码 #include <stdio.h> #include <cuda_runtime.h> ...

  10. xml转json的方法

    .第一种方法 使用JSON-JAVA提供的方法,之前一直使用json-lib提供的方法转json,后来发现了这个开源项目,觉得用起来很不错,并且可以修改XML.java中的parse方法满足自己的转换 ...