bfs(图的最短路径)+优先队列 (2021-8-9)

刺客信条

题意
小A就将操控艾吉奥从佛罗伦萨庄园出发,前往梵蒂冈,夺取教皇权杖。
在整个过程中,每经过一个建筑,都需要花费一定的时间,需要特别注意的是,由于圣母百花大教堂、圣马可大教堂、乔托钟楼都有众多圣殿骑士守护,经过这三个地方时,你需要花费100的时间 ,小A已经急不可耐地想要通关了,所以希望花费最少的时间到达梵蒂冈,请你帮他计算一下,从佛罗伦萨庄园到梵蒂冈,最快需要多少时间?
(注:最短路径不一定耗时最小

输入
第一行有两个整数,表示地图的行数n和列数m,地图为一个n×m的矩阵
接下来有n行,每行m个字符,每个字符是一个数字或大写字母,数字表示经过该建筑需要的时间,字母表示特定建筑(S表示佛罗伦萨的庄园,即起点;E表示梵蒂冈,即终点;A表示圣母百花大教堂;B表示圣马可大教堂;C表示乔托钟楼;A、B、C在每组数据中至多出现一次),每个字符或数字之间用空格分隔
为了降低游戏难度,小A特意调小了地图
0≤n,m≤30
(注:因为n的范围较小,所以二维数组一般可以解决)

输出
输出一个整数,从佛罗伦萨庄园到梵蒂冈的最小用时T

示例1
输入
3 3
S A E
1 2 3
1 B 3

输出
6

思路:
(1)二维矩阵求最短时间,很类似迷宫求最短路径,可以想到bfs(当时我可没想到,想了用floyd最后不知道有几个中介点个数,放弃了)
(2)必须用优先队列(重载运算符),因为路径短,不一定耗时短,在优先队列,每次拿出用时最短的那个点去更新,直到到达终点(精髓)(也是查的)

科普:
bfs操作步骤
(1)放入起点 q.push(1) vis[1]=0
(2)如果队列非空,取队头,找对头周围能达的所有点(未访问)
(3)再放入队列中
(4)队列空,停止

#include<iostream>//有点妙 看的题解 
#include<queue>
using namespace std;
const int maxn=35;
struct Edge{
	int x;
	int y;
	int d;
	//优先队列默认从大到小排
	bool operator < (Edge right) const{
		return d>right.d;//所以符号要反向,从小到大
	}
};
char mp[maxn][maxn];
int value[maxn][maxn];//二维数组ao 经过该点所需的时间
bool vis[maxn][maxn];//是否访问过 (二维ao) 
Edge s,e;
priority_queue<Edge> q;//优先队列 
int n,m;
int dx[4]={1,0,-1,0};//注意是四个方向,不是八个,不能斜着走 
int dy[4]={0,-1,0,1};
int bfs(Edge start){
	q.push(start);//放入起点 
	vis[start.x][start.y]=1;
	Edge tmp,nxt;
	while(!q.empty()){
		tmp=q.top();//优先队列是top 
		q.pop();
		if(tmp.x==e.x&&tmp.y==e.y){//注意:返回条件
			return tmp.d;
		}
		for(int i=0;i<4;i++){
			int nx=tmp.x+dx[i];
			int ny=tmp.y+dy[i];
			if(nx<1||nx>n||ny<1||ny>m){
				continue;
			}
			if(!vis[nx][ny]){
				nxt.x=nx;
				nxt.y=ny;
				nxt.d=tmp.d+value[nx][ny];//精髓 更新时间
				q.push(nxt);
				vis[nx][ny]=1; 
			}
		} 
	} 
}
int main(){

	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>mp[i][j];
			if(mp[i][j]=='S'){
				s.x=i;
				s.y=j;
				s.d=0;//精髓 不可缺 起始点时间为0
			}
			else if(mp[i][j]=='E'){
				e.x=i;
				e.y=j;
			}
			else if(mp[i][j]=='A'||mp[i][j]=='B'||mp[i][j]=='C'){
				value[i][j] = 100; 
			}
			else{
				value[i][j]=mp[i][j]-'0';
			}
		}
	}
	cout<<bfs(s)<<endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值