题目链接:https://hihocoder.com/problemset/problem/1828
题意:
给你一个n*m的图,你要从S走到T,每走一步都要花费1的时间,现在有的房间会有不同,'.'代表空房间,走入后不会发生什么,'B'代表有氧气瓶的房间,每走入一次就能得到一罐氧气瓶(但持续呆在里面不会得到,氧气瓶的携带上限是5个),'P'代表有加速药丸的房间,每走入一次都代表可以减少1的时间(携带无上限,即走进这个房间不消耗时间),'#'代表有毒气的房间,每走入一次需要一罐氧气瓶,并且在其中还有呆一的时间(即走入要消耗1个氧气瓶,消耗2的时间),问这从S走到T的最少花费时间,走不到输入-1。
做法:
最短路,之前也做过一道类似的题目,用类似dp的做法记录最短路,并且每个状态达到过了的直接加上标记,这样最多的情况也就是100*100*5个在优先队列中的放入放出,然后判断答案就好了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
int n,m,k,dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
ll ans;
char mp[105][105];
struct Node
{
int dis,x,y,num;
Node(){}
Node(int dis,int x,int y,int num) : dis(dis),x(x),y(y),num(num){}
bool operator < (const Node& rhs) const{
if(dis!=rhs.dis)
return dis > rhs.dis;
else return num>rhs.num;
}
};
ll dis[105][105][8];
bool vis[105][105][8];
int ck(int x,int y){
if(x<1||x>n||y<1||y>m) return 0;
return 1;
}
void Dijkstra(int stx,int sty,int enx,int eny){
priority_queue<Node> Q;
while(!Q.empty()) Q.pop();
Q.push(Node(0,stx,sty,0));
dis[stx][sty][0]=0;
while(!Q.empty()){
Node u = Q.top(); Q.pop();
if(vis[u.x][u.y][u.num]) continue;
vis[u.x][u.y][u.num] = 1;
//printf("x=%d y=%d dis=%d num=%d\n",u.x,u.y,u.dis,u.num);
for(int i=0;i<4;i++){
int dx=u.x+dir[i][0],dy=u.y+dir[i][1];
if(!ck(dx,dy)) continue;
if(mp[dx][dy]=='#'){
if(u.num==0) continue;
if(u.dis+2< dis[dx][dy][u.num-1]){
dis[dx][dy][u.num-1]=u.dis+2;
Q.push(Node(u.dis+2,dx,dy,u.num-1));
}
}
if(mp[dx][dy]=='.'||mp[dx][dy]=='S'||mp[dx][dy]=='T'){
if(u.dis+1< dis[dx][dy][u.num]){
dis[dx][dy][u.num]=u.dis+1;
Q.push(Node(u.dis+1,dx,dy,u.num));
}
}
if(mp[dx][dy]=='P'){
if(u.dis<dis[dx][dy][u.num]){
dis[dx][dy][u.num]=u.dis;
Q.push(Node(u.dis,dx,dy,u.num));
}
}
if(mp[dx][dy]=='B'){
if(u.dis+1<dis[dx][dy][u.num+1]&&u.num+1<=5){
dis[dx][dy][u.num+1]=u.dis+1;
Q.push(Node(u.dis+1,dx,dy,u.num+1));
}
}
}
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
if(n==0&&m==0) break;
int stx,sty,enx,eny;
for(int i=1;i<=n;i++){
scanf("%s",mp[i]+1);
for(int j=1;j<=m;j++){
for(int k=0;k<=5;k++)
vis[i][j][k]=0,dis[i][j][k]=inf;
if(mp[i][j]=='S')
stx=i,sty=j;
if(mp[i][j]=='T')
enx=i,eny=j;
}
}
ans=inf;
Dijkstra(stx,sty,enx,eny);
for(int i=0;i<=5;i++){
ans=min(ans,dis[enx][eny][i]);
}
if(ans==inf) printf("-1\n");
else printf("%lld\n",ans);
}
return 0;
}