N皇后 八皇后 位运算解法
Posted 317zhang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了N皇后 八皇后 位运算解法相关的知识,希望对你有一定的参考价值。
问题描述
题目链接
解法
? 直接在N*N的棋盘上进行深搜,试探着下棋,也就是回溯法。
? 对于一个皇后来说,我们需要判断她的 八个方向 ,即 主对角线,副对角线,行,列
? 1. 确定状态
? 第一眼的感觉是要用 四个数组来储存情况,但时间上只需要三个 ,把 行 排除在外
? 因为每次搜索的时候,都自动按行搜索,也就是变量 row ,每改变一次,代表了不同的行
? 接下来,分析主对角线 ,对于N*N的矩阵来说,主对角线上的值满足 行和列的差为定值
? 即,做减法得到的下标是唯一的,因为数组没有 负值的索引 所以要 再差值的基础上,加n
? row - col + n 得到唯一的下标,
? 副对角线 ,行 列 之和为定值 row + col
? 列 直接利用下标 储存就行
? 2.试探着下棋 (回溯)
? i 代表列 ,每次搜索按列递进,这样保证了每一列,只可能放一个棋子
? lvis 代表 主对角线的状态 ,rvis 代表副对角线的状态 ,col 代表 列 的状态
? if 那段表示 ,如果 主对角线,副对角线,列 上都没有棋子落下
? 之后 改变状态 ,将 主对角线,副对角线,列 都设置为 1
? dfs(row + 1) 按行递进
? dfs(row + 1)执行完之后,退回到之前的状态:
? lvis,rvis,col 都置为 0 ,在这一行中找下一个可以放的位置
for(int i=1;i<=n;++i){
if(!lvis[i-row+8]&&!rvis[i+row]&&!col[i]){
lvis[i-row+8] = 1;
rvis[i+row] = 1;
col[i] = 1;
ans[row] = i;
dfs(row+1);
lvis[i-row+8] = 0;
rvis[i+row] = 0;
col[i] = 0;
}
}
1.朴素解法(回溯)
#include <bits/stdc++.h>
using namespace std;
const int N =1e2+10;
bool lvis[N],rvis[N],col[N];
int n,tot,ans[N];
void dfs(int row){
if(row == n+1){
tot++;
for(int i=1;i<=8;++i){
cout<<ans[i]<<" ";
}
cout<<endl;
}
else {
for(int i=1;i<=n;++i){
if(!lvis[i-row+8]&&!rvis[i+row]&&!col[i]){
lvis[i-row+8] = 1;
rvis[i+row] = 1;
col[i] = 1;
ans[row] = i;//保存棋子的位置, 第row行,第i列;
dfs(row+1);
lvis[i-row+8] = 0;
rvis[i+row] = 0;
col[i] = 0;
}
}
}
}
int main(){
//cin>>n;
n = 8;
dfs(1);
cout<<tot<<endl;
return 0;
}
2.位运算解法(状态储存方式的不同)
? 根本思路是一样的,拿位运算解,就是把原先用数组储存状态的方式,改变为用 整数 int
? 因为 一个int 占 4个字节 4*8 个bit,所以相当于 含有 32个空间的数组
? 用位运算 大大降低了占用的空间支出
? 基本位运算操作
? 对于改变状态来说,无非就两种 ,1 和 0
? 对于特定位置 1 :
a |= (1<<i);
? 把 1 左移 i 位 ,得到一个32位整数
? 假如 i 为 2
? (省略24位前置 0) 0000 0100
? 假如 i 为 1
? (省略24位前置 0) 0000 0010
? 假如 i 为 7
? (省略24位前置 0) 1000 0000
? 将其与 a 进行 或运算 ,原先 a上的第 i 位, 将被置为 1
? 对于特定位置 0:
a &= ~(1<<i);
? ~运算 ,把各位上的值都取反
? 假如 i 为 2
? (省略24位前置 1) 1111 1011
? 假如 i 为 1
? (省略24位前置 1) 1111 1101
? 假如 i 为 7
? (省略24位前置 1) 0111 1111
? 将其与 a 进行 与运算 ,原先 a 上的第 i 位,将被置为 0
? 判断状态
? x 的第 i 位 是否为 1
bool getbit(int x,int i){
return !((x>>i) & 1);
}
? 把 x 右移 i 位(这样当前 x 的第0 位,就是原先 x 的第 i 位), 和 1进行与运算
完整代码
#include <bits/stdc++.h>
using namespace std;
const int N =1e2+10;
int lvis,rvis,col;
int n,tot,ans[N];
bool getbit(int x,int i){
return !((x>>i) & 1);
}
void dfs(int row){
if(row == n+1){
tot++;
for(int i=1;i<=8;++i){
cout<<ans[i]<<" ";
}
cout<<endl;
}
else {
for(int i=1;i<=n;++i){
if(getbit(lvis,i-row+8)&&getbit(rvis,i+row)&&getbit(col,i)){
lvis |= (1<<(i-row+8));
rvis |= (1<<(i+row));
col |= (1<<i);
ans[row] = i;
dfs(row+1);
lvis &= ~(1<<(i-row+8));
rvis &= ~(1<<(i+row));
col &= ~(1<<i);
}
}
}
}
int main(){
cin>>n;
//n = 8;
dfs(1);
cout<<tot<<endl;
return 0;
}
(C++ 自带 bitset ,可以不用这么麻烦)
只要把 这行
bool lvis[N],rvis[N],col[N];
替换成这行
bitset<N> lvis,rvis,col;
#include <bits/stdc++.h>
using namespace std;
const int N =1e2+10;
bitset<N> lvis,rvis,col;
int n,tot,ans[N];
void dfs(int row){
if(row == n+1){
tot++;
for(int i=1;i<=8;++i){
cout<<ans[i]<<" ";
}
cout<<endl;
}
else {
for(int i=1;i<=n;++i){
if(!lvis[i-row+8]&&!rvis[i+row]&&!col[i]){
lvis[i-row+8] = 1;
rvis[i+row] = 1;
col[i] = 1;
ans[row] = i;
dfs(row+1);
lvis[i-row+8] = 0;
rvis[i+row] = 0;
col[i] = 0;
}
}
}
}
int main(){
//cin>>n;
n = 8;
dfs(1);
cout<<tot<<endl;
return 0;
}
以上是关于N皇后 八皇后 位运算解法的主要内容,如果未能解决你的问题,请参考以下文章