dfs深度优先搜索

前言:老师讲dfs的时候肯定会提到8皇后问题,这是一个经典的组合问题,虽然是老题目了,但小白拿来练习还是很合适的。这篇再来分享一些dfs的题目,然后就开始新内容啦

题目:N皇后问题          N皇后问题

思路: 

  1. 棋盘表示:用二维数组表示棋盘,1 表示放置皇后,0 表示空位。

  2. DFS 递归:从第 1 行开始,逐行尝试放置皇后,递归处理下一行。

  3. 检查函数:判断当前位置是否安全(同行、同列、对角线无皇后)。

  4. 回溯:递归返回后,撤销当前放置,尝试下一个位置。

  5. 计数:如果成功放置 n 个皇后,计数器加一。

#include<iostream>
using namespace std;
int n,cnt;
int a[15][15];
bool check(int x,int y){
	int i,j;
	for(i=1;i<=n;i++){
		if(a[i][y]) return 0;    //同列有皇后 
		if(a[x][i]) return 0;    //同行有皇后 
	}
	for(i=x,j=y;i>=1&&j>=1;i--,j--){ //因为是从上往下放置,只要检查左上角和右上角有无皇后 
		if(a[i][j]) return 0;  //主对角线检查 
	}
	for(i=x,j=y;i>=1&&j<=n;i--,j++){  //副对角线检查 
		if(a[i][j]) return 0;
	}
	return 1;
}
void dfs(int index){
	if(index==n+1){             //成功放置了n个,计数 
		cnt++;
		return;
	}
	for(int i=1;i<=n;i++){
		if(check(index,i)){    //如果安全则放置皇后 
			a[index][i]=1;     //标记 
			dfs(index+1);      //放置下一个 
			a[index][i]=0;     //回溯 
		}
	}
}
int main(){
	cin>>n;
	dfs(1);          //从第一行开始放置皇后 
	cout<<cnt;
	return 0;
} 

写了这么多题,感觉dfs很重要的一点就是回溯呀!  是的,但也不全是。我无意识的都会回溯,wyh的迷宫 这题我+了回溯就超时了,数据量有500,每一步都返回时间复杂度自然高,而这题只是问能不能到达,那就一直搜索,不要重新访问节点,看看能不能到终点就行了/_\,我们在套路的同时也要灵活一点,特别注意数据大小。直接放代码了(学了后面的bfs,可以返回来用bfs做做)

#include<iostream>
using namespace std;
int n,m,sx,sy,flag;
char a[510][510];
void dfs(int x,int y){
	if(a[x][y]=='t'){
		flag=1;
		return;
	}
	if(x<1||x>n||y<1||y>m||a[x][y]=='x') return;
	a[x][y]='x';
	dfs(x-1,y);
    dfs(x+1,y);
    dfs(x,y-1);
    dfs(x,y+1);
	//a[x][y]='.';       不需要回溯
}
int main(){
	int t,i,j;
	cin>>t;
	while(t--){
		flag=0;
		cin>>n>>m;
		for(i=1;i<=n;i++){
			for(j=1;j<=m;j++){
				cin>>a[i][j];
				if(a[i][j]=='s') sx=i,sy=j;
			}
		}
		dfs(sx,sy);
		if(flag) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
} 

需要恢复状态(回溯)的情况:找出所有可能的解;组合/排列问题(需要尝试多种选择)

不需要恢复状态的情况:只需要找到一个解;路径是唯一的,不需要尝试多种可能性(如上一篇的水池数目)

这块就先分享这么多一些典型的题目了,搜索还可以和数论啊什么的结合,复杂起来题目老难了(对于目前的我来说),这几篇文章就只是分享一些基础的思维,谢谢阅读~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值