搜索问题总结

1.前言:

得做些努力,先对搜索的题目下手,希望能有进步。
bfs应该是一种层次搜索,它是通过借助队列实现的。bfs一般可以解决最优,最快情况的问题。bfs的缺点就是占用的空间太大。宽度优先搜索可以解决最短路径、最少操作之类的题目,宽搜的过程中需要将已经访问过的状态保存起来,就可以很好的做到从近到远的搜索。
dfs应该是深度搜索,类似于树的先序搜索,它是通过递归来实现的。dfs可以解决有没有解的问题,能不能走出迷宫。
2.题型

1.地图迷宫
(1)八连通块问题(HDOJ1214,POJ2386)
https://blog.csdn.net/qq_37360631/article/details/77104082
(2)迷宫的最短路径BFS,并输出最短路径
http://blog.csdn.net/qq_37360631/article/details/76862479
(3)迷宫的最少拐弯数BFS(HDOJ1728)
http://blog.csdn.net/qq_37360631/article/details/76999765
(4)深度优先搜索过程中的剪枝
一个结论:起始点 ( x , y ) (x,y) (x,y)和终点 ( d x , d y ) (dx,dy) (dx,dy),那么 a b s ( x − y ) + a b s ( d x − d y ) abs(x-y)+abs(dx-dy) abs(xy)+abs(dxdy)的奇偶性和走的步数的奇偶性相同。
https://blog.csdn.net/qq_37360631/article/details/77017766
(5)记忆化搜索+BFS+剪枝
https://blog.csdn.net/qq_37360631/article/details/77018154
(6)DFS+回溯,打印出所有上升的情况
https://blog.csdn.net/qq_37360631/article/details/77030973
(7)DFS+回溯,字符串搜索,找出满足条件的一个解
https://blog.csdn.net/qq_37360631/article/details/77045227
(8)DFS+回溯,素数打表,素数环问题
https://blog.csdn.net/qq_37360631/article/details/77053502
(9)DFS+翻转棋盘棋子,使全部正面朝上
https://blog.csdn.net/qq_37360631/article/details/77899275
(10)DFS,蓝桥杯地宫取宝,要求从起点到终点恰好取k个礼物(每次取礼物必须满足一定条件),问一共有多少种方法取。
https://blog.csdn.net/qq_37360631/article/details/79766430
(11)DFS+vector,查询一个图中每个结点的父节点。
https://blog.csdn.net/qq_37360631/article/details/79978030
(12)DFS+剪枝,将一系列的小木棍拼成一个长木棍,要求每个长木棍长度相同。(还是不是很清楚…)
https://blog.csdn.net/qq_37360631/article/details/80149802
(13)DFS+回溯,遇到墙面可以选择新的方向,问从起点到终点最少可以转几次方向到达。
https://blog.csdn.net/qq_37360631/article/details/81627951
(14)BFS,将每次更新起点和终点,用N次BFS求和就是结果。
https://blog.csdn.net/qq_37360631/article/details/81630220
(15)DFS+SET,涉及到set的应用,很有意义,打印出所有可能的序列。
https://blog.csdn.net/qq_37360631/article/details/81749691
(16)DFS+bitset,设计到bitset的用法,每次可以翻转一行或者一列,问向上的个数最多是多少个。
https://blog.csdn.net/qq_37360631/article/details/81771564
(17)BFS,给定一个无序树,问能否输出给定的顺序。即问能否用给定顺序BFS进行遍历。
https://blog.csdn.net/qq_37360631/article/details/82388153

3.dfs经典代码举例

/*	Poj2386 
dfs八联通块 
*/
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define For(a,b) for(int a=0;a<b;a++)
#define mem(x) memset(x,0,sizeof(x))
#define sf scanf
#define pf printf
#define maxn 310
int gcd(int a,int b){ return b>0?gcd(b,a%b):a;}
typedef long long ll;
using namespace std;
int n,m,res,ans=0;		//n行m列 
char mp[maxn][maxn];
int dir[8][2]={-1,0,1,0,0,1,0,-1,-1,-1,-1,1,1,-1,1,1};

void dfs(int x,int y){
	mp[x][y]='.';	//这个地方标记为已经访问
	for(int i=0;i<8;i++){
		int dx=x+dir[i][0];
		int dy=y+dir[i][1];
		//判断是否在院子内,是否有积水 
		if(dx>=0&&dx<n&&dy>=0&&dy<m&&mp[dx][dy]=='W')
			dfs(dx,dy);
	} 
}
int main(){
	ans=0;
	cin>>n>>m;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
		//	sf("%c",&mp[i][j]); 用sf后面需要加上getchar()把回车读了 
			cin>>mp[i][j];
		}
	}
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			if(mp[i][j]=='W'){
				dfs(i,j);
				ans++;
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}

bfs经典代码,迷宫最短路径

/*	n*m的矩阵,从左上角走到右下角最少多少步
	#表示墙壁,.表示通行 
3 3
.#.
.##
...
*/
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define For(a,b) for(int a=0;a<b;a++)
#define mem(x) memset(x,0,sizeof(x))
#define Debug(x) cout<<"---> "<<x<<endl;
#define sf scanf
#define pf printf
#define maxn 310
int gcd(int a,int b){ return b>0?gcd(b,a%b):a;}
typedef long long ll;
typedef pair<int,int> P;
//head
int n,m,res=0,ans=0;		//n行m列 
char mp[maxn][maxn];
int d[maxn][maxn];
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};


//求解从(x1,y1)到(x2,y2)的最短距离 
int bfs(int x1,int y1,int x2,int y2){
	queue<P> que;
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++) d[i][j]=inf;
	//将起点放队列,并把这个点的距离标记为0
	que.push(P(x1,y1));
	d[x1][y1]=0;
	
	//不断循环知道队列的长度为0
	while(que.size()){
		P p=que.front(); que.pop();
		if(p.first==x2 &&p.second==y2) break;
		
		for(int i=0;i<4;i++){
			int nx=p.first+dx[i];
			int ny=p.second+dy[i];
			//判断是否可以移动以及是否访问过,距离为Inf就是没访问过 
			if(d[nx][ny]==inf &&mp[nx][ny]!='#'&&nx>=0&&nx<n&&ny>=0&&ny<m) {
				que.push(P(nx,ny));
				d[nx][ny]=d[p.first][p.second]+1;
			}
		}
	} 
	return d[x2][y2];
}
int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>mp[i][j];
		}
	}
	int res=bfs(0,0,n-1,m-1);
	cout<<res<<endl;
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值