ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 A Saving Tang Monk II 最短路dijkstra

题目链接: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;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值