dfs经典例题——n皇后、数的排列

一、n皇后问题843. n-皇后问题 - AcWing题库

题解1:

暴力枚举来搜索,每一行只能有一个皇后,就先按行再按列来枚举,列举每一种情况,即n*n种情况,怎样筛选结果呢,

这道题限制条件有三个,对于对角线,由数学知识(可以自己画个图像)知正对角线横纵坐标相减为定值,即x-y,考虑到数组下标不能为负数,所以x-y+n;反对角线横纵坐标相加为定值,即x+y。来确定对角线 ,只要有xy满足上面任意一个,就标记定值,这样就能筛选满足条件的皇后了。

见下面代码(代码我是参考别人的,不是原创哈,自己写一遍理解一下)

#include<iostream>
using namespace std;

const int N=10;
int n;
char queen[N][N];
bool row[N],col[N],dia[2*N],udia[2*N];

void dfs(int x,int y,int s)
{
	if(y==n) y=0,x=x+1;

	if(x==n)  //行等于n
	{
		if(s==n)  //继续判断,只有在皇后个数等于n时才是正确结果
		{
			for(int i=0;i<n;i++)
			{
					for(int j=0;j<n;j++)
					printf("%c",queen[i][j]);
					printf("\n");
			}
			printf("\n");
		}
		return;
	} 
	
	if(!row[x]&&!col[y]&&!dia[x-y+n]&&!udia[x+y])  //该位置满足,就进入
	{
		queen[x][y]='Q';
		row[x]=true,col[y]=true,dia[x-y+n]=true,udia[x+y]=true;
		dfs(x,y+1,s+1);  //表示这一行已经找到了,不能再用了,从下一列开始,保证了从左到右、从上到下的顺序 
		row[x]=false,col[y]=false,dia[x-y+n]=false,udia[x+y]=false;
		queen[x][y]='.'; //注意这里别漏了,回溯后恢复现场

	}
	
	dfs(x,y+1,s); //上面if里的位置不满足,往下一列查看(从上到下,从左往右,以防漏掉)
	
}

int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	for(int j=0;j<n;j++)
	queen[i][j]='.';
	dfs(0,0,0);
	return 0;
}

题解2:以行枚举搜(类比数的全排列),当处理完了当前行的所有可能性,但没有找到合适的位置放置皇后,时会执行下一行的递归调用;当所有位置都尝试完毕且无法找到合适的位置时,所有循环都结束,函数执行到最后一行`return`语句之后,会返回到上一次递归调用的地方,不断回溯,直到搜完所有可能找到最终结果。

见代码

#include<iostream>
using namespace std;

const int N=10;

int n;
char queen[N][N];
bool dia[2*N],udia[2*N],col[N];

void dfs(int s)  //当前处理的行数
{
	if(s==n)
	{
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<n;j++)
			cout<<queen[i][j];
			cout<<endl;
		}
		cout<<endl;
		return;
	}
	
	for(int i=0;i<n;i++)  //一行一行的搜
	{
		if(!col[i]&&!dia[s+i]&&!udia[n-s+i])
		{
			9queen[s][i]='Q';
			col[i]=dia[s+i]=udia[i-s+n]=true;
			dfs(s+1);
			col[i]=dia[s+i]=udia[i-s+n]=false;
			queen[s][i]='.';
		}
	}
	
	return;
	
}

int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	for(int j=0;j<n;j++)
	queen[i][j]='.';
	dfs(0);
	return 0;
}

二、842. 排列数字 - AcWing题库 

 直接暴搜,见代码

#include<iostream>
using namespace std;

const int N=10;

int n;
int path[N];
bool st[N];

void dfs(int u) //u表示第几个数字,即层数
{
	if(u==n){
		for(int i=0;i<n;i++)
		printf("%d",path[i]);
		printf("\n");
		
	return; //回溯,回到递归的上一步dfs(2)、dfs(1)、dfs(0),依次,每回溯一次就往下循环一下,不放过每一条路
	}
	
	for(int i=1;i<=n;i++)
	{
		if(!st[i]) {  //选择路径
			path[u]=i;
			st[i]=true;
			dfs(u+1);//结束后就是回溯状态
			st[i]=false;  //递归函数结束后一定要记得恢复
		}
	}
}


int main()
{
	cin>>n;
	dfs(0);
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值