刺客信条
题意
小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;
}