補題:2018ACM-ICPC北京網路賽 題A-Saving Tang Monk II
阿新 • • 發佈:2018-11-12
題目連結:
Saving Tang Monk II
題目大意:
給你一個n*m的圖,你要從S走到T,每走一步都要花費1的時間,現在有的房間會有不同,’.'代表空房間,走入後不會發生什麼,'B’代表有氧氣瓶的房間,每走入一次就能得到一罐氧氣瓶(但持續呆在裡面不會得到,氧氣瓶的攜帶上限是5個),‘P’代表有加速藥丸的房間,每走入一次都代表可以減少1的時間(攜帶無上限,其實可以直接認為是走進這個房間不消耗時間,題目就是為了迷惑人寫這麼多),’#'代表有毒氣的房間,每走入一次需要一罐氧氣瓶,並且在其中還有呆一的時間(即走入要消耗1個氧氣瓶,消耗2的時間),問這從S走到T的最少花費時間,走不到輸入-1。
解題思路:
Emmm,比賽中用了BFS+三維vis去寫,結果是過不了最後一個樣例,因為發現第一次訪問到T的不一定是最少時間訪問。gg
於是,試試最短路+分層圖
將圖分成6層,即0-5個氧氣瓶作為分的標準
然後遇到#就往下走一層,時間+2,遇到P就往上走一層,時間+0,其他就是在當前層圖走,時間+1。
程式碼實現即開3維的dis[x][y][ox],第三維代表氧氣數,同樣vis[x][y][ox]也是開三維
然後用dijstra跑一遍最短路即可求出答案
AC程式碼:
#include <bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; char g[150][150]; int dis[150][150][6],vis[150][150][6]; int n,m; int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; struct node{ int x,y; int ox,dis; node(){} node(int _x, int _y, int _ox, int d):x(_x),y(_y),ox(_ox),dis(d){} bool operator<(const node &a)const{ return dis==a.dis? ox > a.ox : dis > a.dis; } }; void dijstra(int x,int y){ priority_queue<node> pq; pq.push(node(x,y,0,0)); dis[x][y][0] = 0; while(!pq.empty()){ node tmp = pq.top(); pq.pop(); if(vis[tmp.x][tmp.y][tmp.ox]) continue; vis[tmp.x][tmp.y][tmp.ox] = 1; for(int i=0; i<4; ++i){ int tx = tmp.x + dir[i][0]; int ty = tmp.y + dir[i][1]; if(tx < 0 || tx >=n || ty <0 || ty >=m) continue; if(g[tx][ty]== '#'){ if(tmp.ox<=0) continue; if(dis[tx][ty][tmp.ox-1] > tmp.dis+2){ dis[tx][ty][tmp.ox-1] = tmp.dis+2; pq.push(node(tx,ty,tmp.ox-1,tmp.dis+2)); } } else if(g[tx][ty] == 'B'){ if(dis[tx][ty][tmp.ox+1] > tmp.dis+1){ dis[tx][ty][tmp.ox+1] = tmp.dis+1; pq.push(node(tx,ty,tmp.ox+1,tmp.dis+1)); } } else if(g[tx][ty] == 'P'){ if(dis[tx][ty][tmp.ox] > tmp.dis){ dis[tx][ty][tmp.ox] = tmp.dis; pq.push(node(tx,ty,tmp.ox,tmp.dis)); } }else{ //S, T或 . if(dis[tx][ty][tmp.ox] > tmp.dis+1){ dis[tx][ty][tmp.ox] = tmp.dis+1; pq.push(node(tx,ty,tmp.ox,tmp.dis+1)); } } } } } int main(){ while(~scanf("%d%d",&n,&m)&&n){ int sx,sy,ex,ey; for(int i=0; i<n; ++i){ scanf("%s",g[i]); for(int j=0; j<m; ++j){ if(g[i][j] == 'S') { sx = i; sy =j; } if(g[i][j] == 'T'){ ex = i; ey = j; } } } memset(vis,0,sizeof(vis)); memset(dis,INF,sizeof(dis)); int ans = INF; dijstra(sx,sy); for(int i=0; i<=5; ++i){ ans = min(ans, dis[ex][ey][i]); } if(ans==INF) cout<<"-1"<<endl; else cout<<ans<<endl; } return 0; }