1. 程式人生 > >ACM/ICPC 2018亞洲區預選賽北京賽站網路賽 A Saving Tang Monk II【分層bfs】

ACM/ICPC 2018亞洲區預選賽北京賽站網路賽 A Saving Tang Monk II【分層bfs】

時間限制:1000ms

單點時限:1000ms

記憶體限制:256MB

描述

《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.

輸入

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.

輸出

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

樣例輸入

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

樣例輸出

-1
8
11

題意:孫悟空在S點,唐僧在T點。孫悟空要去救唐僧。一路上有很多房間, ' . '代表的是普通房間,B代表的是有氧氣瓶的房間,P代表的是有加速藥的房間,#代表毒氣室。孫悟空在沒有氧氣瓶的情況下不能進入毒氣室,在有氧氣瓶的情況下,進入毒氣室後需要休息一個單位時間。孫悟空最多攜帶五個氧氣瓶,但是可以攜帶無數個加速藥丸。加速藥丸可以使下一次移動不費時間(相當於進入P房間無需時間)。

問最需要多少時間可以救出唐僧,如果不行,輸出-1;

採用分層bfs, 把氧氣瓶數量看成一個特徵量。這樣相當於一個三維移動點(x,y,b) b是氧氣瓶數量。

因為加速藥丸可以無限攜帶,所以不作為特徵量。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define M(a,b) memset(a,b,sizeof(a))
const int MAXN = 1e2 +5;
const int INF = 0x3f3f3f3f;
int X[4] = {0,0,-1,1};
int Y[4] = {1,-1,0,0};
char str[MAXN][MAXN];
int  vis[10][MAXN][MAXN];
int n,m,sx,sy;
struct Node
{
    int x,y,t,b;///t是時間,b是氧氣瓶數目
    bool operator<(const Node &a)const///優先佇列返回所用時間少的那一個
    {
        return t>a.t;
    }
};
priority_queue<Node>q;
void init()
{
    M(vis,0);
    while(!q.empty())q.pop();
}
int bfs(int x,int y)
{
    q.push({x,y,0,0});
    while(!q.empty())
    {
        int x1 = q.top().x;
        int y1 = q.top().y;
        int t1 = q.top().t;
        int b1 = q.top().b;
        q.pop();

        if(vis[b1][x1][y1]==0)
            vis[b1][x1][y1] =1;
        else
            continue;


        for(int i=0; i<4; i++)
        {
            int xx = x1 +X[i];
            int yy = y1 +Y[i];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=m)
            {
                if(str[xx][yy] =='T')
                {
                    return t1+1;
                }
                else if(str[xx][yy] == '.'||str[xx][yy] == 'S')///普通房間,時間+1
                {
                    q.push({xx,yy,t1+1,b1});
                }
                else if(str[xx][yy] == '#' && b1>0)///有氧氣瓶的情況下進入毒氣室,時間+2,氧氣瓶數-1
                {
                    q.push({xx,yy,t1+2,b1-1});
                }
                else if(str[xx][yy] == 'B')///進入氧氣瓶室,氧氣瓶數+1,但不大於5。
                {
                    q.push({xx,yy,t1+1,min(5,b1+1)});
                }
                else if(str[xx][yy] == 'P')///進入加速藥丸室,不花費時間。
                {
                    q.push({xx,yy,t1,b1});
                }
            }
        }

    }
    return -1;
}
int main()
{
    while(scanf("%d %d",&n,&m)&&n&&m)
    {
        init();
        for(int i=1; i<=n; i++)
        {
            scanf("%s",str[i]+1);
        }
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                if(str[i][j]=='S' )///確定起點
                {
                    sx = i;
                    sy = j;
                }
            }
        }
        int ans = bfs(sx,sy);
        printf("%d\n",ans);
    }
    return  0;
}