ACM/ICPC 2018北京网络赛 HihoCoder - 1828 Saving Tang Monk II(搜索)

题目链接

题目

《Journey to the West》(also 《Monkey》) is one of the Four Great Classical Novels of Chinese literature. It was written by Wu Cheng’en during the Ming Dynasty. In this novel, Monkey King Sun Wukong, pig Zhu Bajie and Sha Wujing, escorted Tang Monk to India to get sacred Buddhism texts.

During the journey, Tang Monk was often captured by demons. Most of demons wanted to eat Tang Monk to achieve immortality, but some female demons just wanted to marry him because he was handsome. So, fighting demons and saving Monk Tang is the major job for Sun Wukong to do.

Once, Tang Monk was captured by the demon White Bones. White Bones lived in a palace and she cuffed Tang Monk in a room. Sun Wukong managed to get into the palace, and he wanted to reach Tang Monk and rescue him.

The palace can be described as a matrix of characters. Different characters stand for different rooms as below:

‘S’ : The original position of Sun Wukong

‘T’ : The location of Tang Monk

‘.’ : An empty room

‘#’ : A deadly gas room.

‘B’ : A room with unlimited number of oxygen bottles. Every time Sun Wukong entered a ‘B’ room from other rooms, he would get an oxygen bottle. But staying there would not get Sun Wukong more oxygen bottles. Sun Wukong could carry at most 5 oxygen bottles at the same time.

‘P’ : A room with unlimited number of speed-up pills. Every time Sun Wukong entered a ‘P’ room from other rooms, he would get a speed-up pill. But staying there would not get Sun Wukong more speed-up pills. Sun Wukong could bring unlimited number of speed-up pills with him.

Sun Wukong could move in the palace. For each move, Sun Wukong might go to the adjacent rooms in 4 directions(north, west,south and east). But Sun Wukong couldn’t get into a ‘#’ room(deadly gas room) without an oxygen bottle. Entering a ‘#’ room each time would cost Sun Wukong one oxygen bottle.

Each move took Sun Wukong one minute. But if Sun Wukong ate a speed-up pill, he could make next move without spending any time. In other words, each speed-up pill could save Sun Wukong one minute. And if Sun Wukong went into a ‘#’ room, he had to stay there for one extra minute to recover his health.

Since Sun Wukong was an impatient monkey, he wanted to save Tang Monk as soon as possible. Please figure out the minimum time Sun Wukong needed to reach Tang Monk.

Input

There are no more than 25 test cases.

For each case, the first line includes two integers N and M(0 < N,M ≤ 100), meaning that the palace is a N × M matrix.

Then the N×M matrix follows.

The input ends with N = 0 and M = 0.

Output

For each test case, print the minimum time (in minute) Sun Wukong needed to save Tang Monk. If it’s impossible for Sun Wukong to complete the mission, print -1

Sample Input

2 2
S#
#T
2 5
SB###
##P#T
4 7
SP.....
P#.....
......#
B...##T
0 0

Sample Output

-1
8
11

题目大意

给你一个迷宫,S是起点,T是终点,要从S走到T,判断最少的时间,无法走出迷宫则输出-1。
中间#表示毒气室,进入毒气室必须有氧气瓶,当进入毒气室需要逗留一个时间单位。B表示的地方则为有氧气瓶的房间,每次经过可以拿一个氧气瓶,手中的氧气瓶最多不超过5个,‘.’就代表普通的路,P代表加速药丸,可以加速一个时间单位。

我的理解

我的想法就是跑一个bfs,因为每个或节点扩展的下一个节点的时间未必是增加的。所以用一个优先队列作为bfs的队列。
而判断一个点是否走过的vis数组不只是简单的两位数组记录走过的点的位置,而是增加一个第三维度,代表氧气瓶的个数,因为当走到同一个点时,但手中的氧气瓶个数不相同的时候,是不同的状态,需要不同的记录。
然后就是一个正常的bfs了。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 110;

int vis[maxn][maxn][6];
char mp[maxn][maxn];
int n,m;
int dir[4][2] = {0,1,1,0,0,-1,-1,0};
struct node{
	int x,y;
	int ox;
	int dis;
	bool operator<(node obj)const{
		return dis>obj.dis;
	}
	node(){}
	node(int X,int Y,int Ox,int Dis){
		x = X;
		y = Y;
		ox = Ox;
		dis = Dis;
	}
};

int bfs(int sx,int sy){
	priority_queue<node> pq;
	pq.push(node(sx,sy,0,0));
	vis[sx][sy][0] = 1;
	while(pq.size()){
		node now = pq.top();
		pq.pop();
//		cout<<endl<<"& "<<now.x<<" "<<now.y<<" "<<now.ox<<" "<<now.dis<<endl;
		if(mp[now.x][now.y] == 'T'){
			return now.dis;
		}
		for(int i = 0;i<4;i++){
			int tx = now.x+dir[i][0];
			int ty = now.y+dir[i][1];
			if(tx<1 || ty<1 || tx>n || ty>m){
				continue;
			}
			int tox = now.ox;
//			cout<<tx<<" "<<ty<<" "<<tox<<" "<<now.dis<<endl;
			if(vis[tx][ty][tox])	continue;
			vis[tx][ty][tox] = 1;
			if(mp[tx][ty]=='B'){
				pq.push(node(tx,ty,min(5,tox+1),now.dis+1));
			}else if(mp[tx][ty] == '#'){
				if(tox<=0)	continue;
				pq.push(node(tx,ty,tox-1,now.dis+2));
			}else if(mp[tx][ty] == 'P'){
				pq.push(node(tx,ty,tox,now.dis));
			}else{
				pq.push(node(tx,ty,tox,now.dis+1));
			}
		}
	}
	return -1;
}

int main(){
	int sx,sy;
	while(scanf("%d%d",&n,&m) && n+m){
		memset(vis,0,sizeof(vis));
		for(int i = 1;i<=n;i++){
			scanf("%s",mp[i]+1);
		}
		bool fdst = false;
		for(int i = 1;i<=n;i++){
			for(int j = 1;j<=m;j++){
				if(mp[i][j] == 'S'){
					sx = i;
					sy = j;
					fdst = true;
					break;
				}
			}
			if(fdst)	break;
		}
		int res = bfs(sx,sy);
		printf("%d\n",res);
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值