深度优先搜索(DFS)和广度优先搜索(BFS)(学习总结)

深度优先搜索DFS:
①定义:是一种枚举所有完整路径以遍历所有情况的搜索方法。
②如何实现DFS:
使用栈较麻烦。
类比斐波那契数列,可以使用递归这种方式来实现DFS。使用递归系统会调用叫系统栈的东西存放递归中的每一层状态,本质还是栈实现。
③例子
(1)全排列(DFS思想)
求1 2 3或1 2 3 4全排列可以使用几个for循环解决,但当求1到n(n小于等于10)用for不能解决则利用递归。

#include <iostream>
using namespace std;
int n;
int book[20];//初始值为0 
int res[20];
void dfs(int num){
	if(num==n){
		for(int i=0;i<n;i++){
			cout<<res[i]<<" ";
		}
		cout<<endl; 
		return;
	}
	for(int i=1;i<=n;i++){
		if(!book[i]){
			book[i] =1;//标记 
			res[num] = i;
			dfs(num+1);
			book[i] = 0;//取消标记 
		}
	}
}
int main(){
	cin>>n;
	dfs(0);
	return 0;
}

(2)经典迷宫问题
题目链接:https://www.luogu.com.cn/problem/P1605
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
int n,m,t,SX,SY,FX,FY,ans;
int Map[10][10];//为一表示走过或有障碍物 
bool OK(int,int);
int dir[][2]={
  {-1,0},//上
  {0,1},//右
  {1,0},//下
  {0,-1},//左 
};
bool OK(int x,int y){//保证坐标合法是否越界 
	return x>=1&&x<=n&&y>=1&&y<=n;
}
void dfs(int xx,int yy){
	if(xx==FX&&yy==FY){
		ans++;
		return ;
	}
	for(int i=0;i<4;i++){
		int nx = xx+dir[i][0];
		int ny = yy+dir[i][1];
		if(OK(nx,ny)&&!Map[nx][ny])//坐标合法并且没有障碍物并且没有走过,应该标记它
		{
			Map[nx][ny] = 1;
			dfs(nx,ny);
			Map[nx][ny]=0;
		 } 
	}
} 
int main(){
	cin>>n>>m>>t; 
	cin>>SX>>SY>>FX>>FY;//起点和终点 
	int x;int y;
	while(t--){
		cin>>x>>y;
		Map[x][y] = 1;//标记为1 
	}
	Map[SX][SY] = 1;//起点标记 
	dfs(SX,SY);
	cout<<ans<<endl;
	return 0;
} 

广度优先搜索BFS:
①定义:到达岔口,先访问从岔道口能直接到达的所有结点,再按照这些结点被访问顺序依次访问它们能直接到达的所有结点,直到所有结点都被访问为止(类似水面石子落水形成的水波)。
②如何实现BFS:
一般由队列实现,总是按照层次的顺序遍历(层次遍历)。
在这里插入图片描述

连通块:一个图中任意两个结点之间都能相互到达。
如图:
在这里插入图片描述

③例子:
01迷宫(连通块+BFS算法)
题目链接:https://www.luogu.com.cn/problem/P1141
在这里插入图片描述
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
int n,m;
bool OK(int,int);
int book[1010][1010];//标记数组初始值为0, 
char Map[1010][1010];
struct Node{
	int x,y;
	Node(int xx,int yy){
		x=xx;
		y=yy;
	}
};
//枚举的四种坐标 
int dir[][2]={
   {-1,0},//上 
   {0,1},//右
   {1,0},//下
   {0,-1}//左 
};
bool OK(int xx,int yy){
	return xx>=0&&xx<n&&yy>=0&&yy<n;
}
void BFS(int xx,int yy){
	if(book[xx][yy]) return ;
	queue<Node> q;
	q.push(Node(xx,yy)); 
	book[xx][yy] = 1;//起始点已经走过
	vector<Node> v;//存连通块中有哪些节点
	while(!q.empty()){//空则结束 
		Node t = q.front();q.pop(); //取对象坐标
		v.push_back(t);
		if(Map[t.x][t.y]=='0'){
			for(int i=0;i<4;i++){
			int nx = t.x+dir[i][0];
			int ny = t.y+dir[i][1];	
			if(OK(nx,ny)&&Map[nx][ny]=='1'&&!book[nx][ny]){
				book[nx][ny]=1;//标记访问
				q.push(Node(nx,ny));//加入队列 
			    }
			}
		} 
		else{
			for(int i=0;i<4;i++){
			int nx = t.x+dir[i][0];
			int ny = t.y+dir[i][1];	
			if(OK(nx,ny)&&Map[nx][ny]=='0'&&!book[nx][ny]){
				book[nx][ny]=1;//标记访问
				q.push(Node(nx,ny));//加入队列 
			    }
			}
		} 
	} 
	for(int i=0;i<v.size();i++){
		book[v[i].x][v[i].y] = v.size();/*这里非0表示已经访问过了,
		所以我这个book标记数组,记录是否访问过的同时记录答案 */ 
	}
} 
int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++){
		cin>>Map[i];
	}
	int x,y;
	while(m--){
		cin>>x>>y;
		x--;y--;//输入从0开始 
		BFS(x,y);
		cout<<book[x][y]<<endl;
	}
	return 0;
} 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值