1. 程式人生 > >補題:2018ACM-ICPC北京網路賽 題A-Saving Tang Monk II

補題:2018ACM-ICPC北京網路賽 題A-Saving Tang Monk II

題目連結:
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;
}