P1219 八皇后 Checker Challenge
https://www.luogu.com.cn/problem/P1219
八皇后问题是一个经典的回溯算法问题,目标是在一个8x8的棋盘上放置8个皇后,使得它们互不攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上。
深度优先搜索(DFS)是一种常用的解决八皇后问题的方法。下面是一个使用DFS解决八皇后问题的代码示例
#include<iostream>
#include<stdio.h>
using namespace std;
const int maxn=14;
int cnt,n;
//col列 pri 对角线 11 22 33 sec 对角线 13 22 31 ans[i]表示第i行 ans[i]列放入皇后
int col[maxn],pri[2*maxn],sec[2*maxn],ans[maxn];
void pr(){
for(int i=1;i<=n;i++){
if(i!=n)printf("%d ",ans[i]);
else printf("%d",ans[i]);
}
puts("");
}
void dfs(int dep){//递归到当前行
if(dep>n){
cnt++;
if(cnt<=3)pr();
return;
}//搜索到边界
for(int i=1;i<=n;i++){//循环每一列
//当前列未放 对角线1未放 对角线2未放
if(!col[i] && !pri[i-dep+maxn] && !sec[i+dep]){
ans[dep]=i;//记录结果
col[i]=1;pri[i-dep+maxn]=1;sec[i+dep]=1;
dfs(dep+1);
col[i]=0;pri[i-dep+maxn]=0;sec[i+dep]=0;//回溯
}
}
}
int main(){
scanf("%d",&n);
dfs(1);//从第一行开始搜索
printf("%d",cnt);
}
还是N皇后
https://www.luogu.com.cn/problem/P1562
#include<bits/stdc++.h>
using namespace std;
int n,ans,End,mmap[20];
/*
从第1行开始放入每一行,直到放入n行 一个方案结束
在尝试放入每一行的具体哪个列时 需要确认此列、左对角线、右对角线是否已放
row行 ld左斜线 rd 右斜线 col 列
*/
void dfs(int row,int ld,int rd,int col) {
if(row>n){//前面已经放到n行 形成一个方案
ans++;
return;
}
/*
可以分三步来理解:
1、先|方向找到最终的位置
2、取反(~)
3、用End &上,去掉多余的1。
至于End是什么,其实就是(1>>n)-1即n位的1,n位前的0回被抹掉,
表示可放置的1(0取反)不受影响
n=4时 0010 0代表可放 1代表不可放
下一行左方不能放 0100
下一行右方不能放 0001
下一行下放不能放 0010
0111不可放
因此对三个数或运算则可得0100|0001|0010=0111
可以看出只有最高位0可以放 ,但二进制快速找0只能按位找,需要找一种高效方法
0111取反 1000 我们可以通过lowbit找1 通过如下位运算即可 x&(-x)
由于0111可能前面有很多0,000000000000111 取反后 111111111111000
需要想一种办法把前面无用0去除,因为那些已经超出了n的范围,不能放
我们需要构造n个1,比如 n=4 1<<4-1=1111 和前面 111111111111000 按位与 &
1111&111111111111000=1000
*/
int pos=End&(~(col|ld|rd|mmap[row])),p;
while(pos){
p=pos&(-pos);//用lowbit原理
pos-=p; //把用过的可能性减掉
dfs(row+1,(ld+p)<<1,(rd+p)>>1,col+p); //状态转移方程,下一行的状态
}
}
int main() {
char s[20];
scanf("%d\n",&n); //这是个坑点!!!cin会读进换行符
End=(1<<n)-1; //初始n个1 消除多余n位前面的1
for(int i=1;i<=n;i++){
fgets(s,20,stdin);//输入本行
for(int j=1;j<=n;j++){
//这个东西其实就是手动造出表示起始状态的二进制数,就是遇到" . "
//就放1表示不能放,如果没到第n列,就不停的往后补零
mmap[i]=(s[j-1]=='.')+(mmap[i]<<1);//输入对应0 1 用二进制对应整数表示
}
}
dfs(1,0,0,0);//第一行开始dfs
printf("%d",ans);//输入结果
return 0;
}
/*
4
**.*
*.*.
****
****
*/
N皇后问题
http://acm.hdu.edu.cn/showproblem.php?pid=2553
#include<bits/stdc++.h>
using namespace std;
int N,num;
const int MAXN=15;
int col[MAXN],leftCol[2*MAXN],rightCol[2*MAXN],ans[MAXN];
void dfs(int depth){
if(depth==N+1){
num++;
return;
}
for(int i=1;i<=N;i++){
if(!col[i] && !leftCol[i-depth+MAXN] && !rightCol[i+depth]){
col[i]=1;
leftCol[i-depth+MAXN]=1;
rightCol[i+depth]=1;
dfs(depth+1);
col[i]=0;
leftCol[i-depth+MAXN]=0;
rightCol[i+depth]=0;
}
}
}
int main(){
while(cin>>N){
if(N==0) break;
/*
剪枝 如果未计算过 dfs计算放入ans数组
计算过则直接读取
*/
if(ans[N]==0){
memset(col,0,sizeof(col));
memset(leftCol,0,sizeof(leftCol));
memset(rightCol,0,sizeof(rightCol));
dfs(1);
ans[N]=num;
num=0;
}
printf("%d\n",ans[N]);
}
}