对于DFS和BFS的思考【II】 洛谷P1605迷宫、P1443马的遍历

        DFS是一条路走到黑,很多DFS模板题就是有关迷宫问题,迷宫问题包括但不限于从起点走到终点有多少种方案走法,洛谷P1605就是迷宫模板题(传送门:迷宫 - 洛谷)。按照DFS不撞南墙不回头的思路,这道题应该是信手捏来的吧。代码如下:

#include<bits/stdc++.h>

#define int long long 
using namespace std;
const int N=1e7+5;
int ans=0,x_[5]={0,1,0,-1},y_[5]={1,0,-1,0};//x_[],y_[]模拟方向数组 
int n,m,t,start_x,start_y,end_x,end_y;
int mp[20][20],vis[20][20];//mp地图,vis作为监视数组判断是否已经来过这个点 
void dfs(int x,int y){
    if(x==end_x&&y==end_y){//到了终点后方案数就++并且return 
        ans++;
        return ;
    }
    for(int i=0;i<4;i++){
        int dx=x+x_[i];
        int dy=y+y_[i];
        if(dx>=1&&dy>=1&&dx<=n&&dy<=m&&mp[dx][dy]==0&&!vis[dx][dy]){//这里老规矩 判断越界 vis判断没来过 mp[dx][dy]判断是否为障碍物 
            vis[dx][dy]=1;//该点没来过且不是障碍物 所以该点目前可行 标记此点已来过 
            dfs(dx,dy);//从这里回溯出来后说明该点无解 回溯vis[][]为0未标记过 
            vis[dx][dy]=0;
        }
    }
    return ;
}
void solve(){
    cin>>n>>m>>t>>start_x>>start_y>>end_x>>end_y;
    for(int i=1;i<=n;i++){
    	for(int j=1;j<=m;j++){
    		mp[i][j]=0;//初始化全是0 
		}
	}
	for(int i=1;i<=t;i++){
		int a,b;
		cin>>a>>b;//对于障碍 设置为1 
		mp[a][b]=1;
	}
	vis[start_x][start_y]=1;//一定要有这句 你的起点肯定来过所以为1,不然方案数可能会变成答案的2倍(->->和->折回再->->); 
    dfs(start_x,start_y);
    cout<<ans<<endl;
}
signed main(){
        solve();
    return 0;
}

于是写到这里对深搜的理解就好多了,正准备接着写洛谷题单时,发现这道1443感觉又像是迷宫了,不过没有障碍物了,走的方向也从4个变成了8个,第一反应换汤不换药依葫芦画瓢继续用DFS写,大不了用min()来维护最少次数吧。但问题是如果每次都一条路走到黑,这题有尽头吗?用深搜每个点可能不止考虑一次,所以用监视数组显然不行,怎么办呢?于是想到用BFS。

BFS广度优先搜索,就是地毯式搜索,可以理解为病毒扩散的样子:

(图很丑见谅)

他的搜索顺序便是 

 即3,4是一同搜索,5 6 7 8 9 10是一同搜索,可以理解为去学校厕所,厕所门全关了,DFS是敲门→开门→进去查看,而BFS是先全敲一次门,然后把所有门打开,全部一起查看(可能有点怪);但可以想想这个过程,所以DFS可以用stack栈或者递归来写,BFS就是用queue队列来写,对于这道题就要用BFS:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+5;
int x_[10]={1,1,-1,-1,2,2,-2,-2};//8个方向模拟的方向数组 
int y_[10]={2,-2,2,-2,1,-1,1,-1};
int mp[500][500];
struct node{
	int x,y,c;
};//用结构体x,y坐标和c最短次数 
queue<node>que;//用队列存结构体写BFS 
void solve(){
	 int n,m,start_x,start_y;//简单输入 
	 cin>>n>>m>>start_x>>start_y;
	 for(int i=1;i<=n;i++){ 
	 	for(int j=1;j<=m;j++){
	 		mp[i][j]=-1;//初始化为-1,题目说了去不了的地就是-1,干脆就写-1了 
		 }
	 }
	 mp[start_x][start_y]=0;//同样是初始化 
	 que.push((node){start_x,start_y,0});//存进队列 
	 while(!que.empty()){//这里就是BFS的模板 
	 	node f=que.front();
	 	que.pop();
	 	for(int i=0;i<8;i++){//八个方向 
	 		int dx=f.x+x_[i];//和DFS异曲同工 
	 		int dy=f.y+y_[i];
	 		if(mp[dx][dy]==-1&&dx>=1&&dy>=1&&dx<=n&&dy<=m){//不同点在于在该点处可达的8个方向点 
	 			mp[dx][dy]=f.c+1;//如果为-1即没来过的点,那么最少次数一定是该点处次数+1,可以停下来理解理解 
	 			que.push((node){dx,dy,mp[dx][dy]});//存进队列 
			 }
		 }
	 }
	 for(int i=1;i<=n;i++){
	 	for(int j=1;j<=m;j++){
	 		printf("%-5d",mp[i][j]);//简单输出 
		 }
		 cout<<endl;
	 }
}
signed main(){
	solve();
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值