【无标题 蓝桥杯 迷宫的bfs dfs 解法(c++) (菜鸟版)

hello各位看官老爷, 这是菜鸡铭的第一篇博客,本人目前接触算法刚刚两个多月, 实力确实垃圾,众爱卿可能会发问: 汝如此垃圾为何还要写博客?写博客的目的: 一来是用博客记录自己做题的思路方便复习,二来因为我是初学者,在写这篇题解时可以更多的从初学者的视角来讲解,相信看官中肯定会有很多初学的bro经历过在茫茫的博客海洋中, 死都找不到一篇自己能看懂的。

本篇文章  emmmm 在别人的博客中学会了, 自己写一篇emmm,应该,算是原创? 要是不算咋整啊这玩意;

不管了 正文action:

 

 讲题:

1是障碍0是通道 最后咱们找到的路径 要优先满足最短,还要满足字典序最小 就是能用'D'就不用'L',

ok 上强度了everybody。

这道题 可用dfs, bfs两种做法,网上大部分的答案都是dfs, 但是我更偏向于bfs, why?  因为一般来说题目说要找“最优解” 基本上都是bfs, 题目要是说找到”可行解“那就dfs, 而且bfs, 他是模板啊!!!对于初学者不要太友好,

bfs 

#include <bits/stdc++.h>
using namespace std;
const int N = 5, maxn = 7;
int dirx[4] = {1,0,0,-1};
int diry[4] = {0,-1,1,0};
char dirct[4] = {'D', 'L', 'R', 'U'};
int vis[N][maxn] = {0}; //代表我是否来到过这个点 
int map_[N][maxn] = {{0,0,0,0,0,0,0},{0,0,1,0,0,0,0},{0,0,0,0,1,0,0},{0,0,0,1,0,0,1},{0,1,1,0,0,0,0}};
struct node { //记录每一个点的坐标(x,y) 
	int x, y;
	string road;  //记录走到这个点需要走的路径 
	node (int a, int b){
		x = a;
		y = b;
	}
};
bool yuejie (int x, int y){//判断当前的点是否出界(出地图) 
	if (x < 1 || y < 1 || x > 4 || y > 6){
		return false;
	}
	else return true;
	
}
int main (){
	queue<node>p;//队列 用来装点的 
	vis[1][1] = 1;//刚开始 起点我来过了,标记一下 
	node t (1, 1);//设置一个node类型的t 坐标是起点 
	t.road = "";//走到起点路径是空 (还没走呢当然是空)
	p.push(t); //让起点入队列 
	
	while (!p.empty()){
		node Q = p.front();
		p.pop();
		if (Q.x == 4 && Q.y == 6){
			cout << Q.road; //到出口了// 输出路径
			//bfs好在这里 只要抵达出口 就一定是最优解 下面告诉大家为什么 
			break;
		}
		for (int i = 0; i < 4; i ++){//遍历四个方向 
			int tx = Q.x + dirx[i];//新坐标的纵坐标 = 当前纵坐标 + dirx 
			int ty = Q.y + diry[i];//例如i=0时 相当于Q.x + 1, Q.y + 0,
			//纵坐标+1 横坐标不变 相当于dirct[0] ('D'); 
			if (yuejie(tx, ty) && vis[tx][ty] == 0 && map_[tx][ty] == 0){
				//如果没出界 并且这个新坐标没来过 并且新坐标是道路‘0’不是障碍‘1’; 
				node temp(tx, ty); //设置一个node类型的temp; 
				temp.road = Q.road + dirct[i];//temp这个点的路径等于原来的路径加上当前方向; 
				p.push(temp);
				vis[tx][ty] = 1;//标记该点来过; 
			} 
		}
	}
	return 0;
}

看到代码可能会有些蒙,咱们一步步来,咱们用的是测试用例  但是 咱们要在这个迷宫的左边界和上边界,加上零变成酱紫 这样咱们的起点就是(1, 1)比较方便

int dirx[4] = {1,0,0,-1};
int diry[4] = {0,-1,1,0};
char dirct[4] = {'D', 'L', 'R', 'U'};

 我们假设这个迷宫有一个坐标轴,x为纵轴,y为横轴,设向下为x正方向,向右为y正方向,那么我让当前的坐标的横坐标纵坐标分别加上 dirx,diry是不是就产生了新坐标,新坐标分别在当前坐标的下左右上

 问题来了 为啥bfs它直接就是最优解, 它是如何运行的呢?

 看这个图, tt.road 代表每走到一个新的点所走的路径, 可以发现 D 是点(2,1) DD是(3,1), DR 是(2,2) bfs在干啥呢, 它在遍历每一个可以遍历的点 走到(2,1)时, 优先向下走(DD) 然后是左但是出界,右可以(DR), 上不行,因为上面的点vis == 1来过了

接下来DDR DRR DRRU DRRUR 发现啥了吗? DD开头的路径没了!! 咋回事儿捏,DDR是点(3,2) 右边是障碍 左边是(3,1)来过了, 下边是障碍 上边有DR(2,2)了 来过了, 所以DDR(3,2)他憋死了动不了, 

总结bfs就是很多条路径一起走, 能到出口的 最先到达出口的, 肯定是路径最短最优秀的;

okok 接下来dfs, dfs就很常见了,

#include <bits/stdc++.h>
using namespace std;
const int N = 5, M = 7;
int map_[N][M] = {{0,0,0,0,0,0,0},{0,0,1,0,0,0,0},{0,0,0,0,1,0,0},{0,0,0,1,0,0,1},{0,1,1,0,0,0,0}};
int vis[N][M] = {0};
int mins[N][M];    //记录走到点x,y的最小步数 初始值赋值为无穷大;
int dirx[4] = {1, 0, 0, -1};
int diry[4] = {0, -1, 1, 0}; 
char dirct[4] = {'D', 'L', 'R', 'U'};
char a[N * M + 10] = {'0'};
int beststep = 2e6;
string ans;
bool yuejie (int x, int y){
	if (x < 1 || y < 1 || x > N -1 || y > M - 1){
		return false;
	}
	return true;
}
void dfs (int x, int y, int step){
	if (step > beststep){
		return;
	}
	if (x == N - 1 && y == M - 1){  //到达出口 
	      string temp;
	      for (int i = 0; i <= step - 1; i ++){
	      	temp += a[i];
		  }
		if (step < beststep){
			ans = temp;
			beststep = step;
		}
	    if (step == beststep && temp < ans){
	    	ans = temp;
	    }
	}
	for (int i = 0; i < 4; i ++){  //四个方向 
		int tx = x + dirx[i];
		int ty = y + diry[i];
		if (yuejie(tx, ty) && map_[tx][ty] == 0 && vis[tx][ty] == 0 && step + 1 <= mins[tx][ty]){
			vis[tx][ty] = 1;
			mins[tx][ty] = step + 1;
			a[step] = dirct[i];
			dfs(tx, ty, step + 1);
			vis[tx][ty] = 0;
		}
	}
}
int main (){
	memset (mins, 1, sizeof (mins));
	vis[1][1] = 1;
	dfs (1, 1, 0); //坐标 and 步数; 
	cout << ans << endl;
	return 0;
}

其实跟bfs大部分是一样的,多了一个a字符数组用来存储路径, 最后到终点找到最优路径的时候将路径一个个的放到字符串里, 由于是dfs 你会找到很多个解, 这些解可能长度不一样 或者长度一样但是字典序更优秀, 这些时候我们都需要将更优秀的字符串给到ans 直到全部遍历结束 输出最优ans;

            vis[tx][ty] = 1;
			mins[tx][ty] = step + 1;
			a[step] = dirct[i];
			dfs(tx, ty, step + 1);
			vis[tx][ty] = 0;

vis = 1; 标记这个点我现在来到了, 然后dfs, dfs结束之后 需要回溯, 也就是重新让这个点没走过, 这个不知道各位能不能理解, 为什么要回溯呢, 因为dfs 遍历每一种可能, 这么多种路径, 他们可能都会经过这个tx,ty这个点所以当我某次dfs结束之后就将这路径上的所有点都vis = 0;就是下次dfs寻找其他路径的时候还可能经过这些点, emmm 怎么说呢, 明显dfs要稍微难懂,考虑的可能性更多, 更细节,而bfs是模板 先是一个队列 放入起点, while循环 将队列首元素取出来 for循环遍历四个方向, 如果符合条件就让新坐标入队列, 标记这个点来过了, 最后如果到出口了就输出终点的路径,清晰简单明了,debug思路也更清晰, 

所以 对于新手, 我强烈建议各位在比赛时可以多用bfs;  dfs固然有好的地方 但是 我感觉 水太深我把握不住, ok today的铭少讲堂到此为止; 

 第一篇博客写这么长, 放在我十九年的人生中也是相当炸裂的, 以后会长期更新滴, 啊对,有问题随时指出, 感谢大佬!

  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值