深度优先搜索-八皇后

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]);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值