1. 程式人生 > >ACM/ICPC 2018亞洲區預選賽北京賽站網絡賽 A、Saving Tang Monk II 【狀態搜索】

ACM/ICPC 2018亞洲區預選賽北京賽站網絡賽 A、Saving Tang Monk II 【狀態搜索】

ddd namespace bfs lease use break 猴子 解法 nal

任意門:http://hihocoder.com/problemset/problem/1828

Saving Tang Monk II

時間限制: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

題意概括:

給一個 N * M 的地圖,孫悟空初始位置在 S ,唐僧位置在 T。中間地形有:

“ . " :代表平地,暢通無阻;

“ P ”:此處有加速藥丸,藥丸可以使孫悟空下一次移動花費時間為0(每次進入該地形只能拿一個,當然孫悟空可以進入無限次拿無限個);

“ B ”:此處有氧氣,氧氣用於通過有毒氣的地形(每次進入該地形只能拿一個,孫悟空最多可以拿 5 個氧氣);

“ # ”:此處有毒氣,通過這裏需要花費一個氧氣(即無氧氣不能進入這裏),通過毒氣區的孫猴子需要一分鐘恢復健康。

孫悟空每走一步花費一分鐘,求孫悟空成功拯救唐僧的最短時間。如果無法救人輸出“ -1 ”。

解題思路:

一、狀態搜索(BFS+dp)

狀態:dp[ x ][ y ][ N ] : 當前在(x, y)手裏有 N 瓶氧氣的最少花費時間;

狀態轉移:

當前位置(X,Y),轉移位置(TX,TY)

經過 “ S ” 或者 “ . " 時:無限制條件,花費的只是時間,所以 dp[ TX ][ TY ][ N ] = min( dp[ TX ][ TY ][ N ], dp[ X ][ Y ][ N ] + 1);

經過“ P ” 時:拿到藥丸立即用和後面用其實對於總時間是沒有影響的,所以拿到就用,相當於經過這種地區不需要花費時間

      即:dp[ TX ][ TY ][ N ] = min( dp[ TX ][ TY ][ N ], dp[ X ][ Y ][ N ] );

經過“ B ” 時:第一種情況:氧氣未滿,肯定要帶上一瓶氧氣:dp[ TX ][ TY ][ N + 1 ] = min( dp[ TX ][ TY ][ N + 1 ], dp[ X ][ Y ][ N ] + 1);

      第二種情況:氧氣已滿,這種跟經過平地一樣:dp[ TX ][ TY ][ N ] = min( dp[ TX ][ TY ][ N ], dp[ X ][ Y ][ N ] + 1);

經過“ # ”時:沒有氧氣,無法進入。

      有氧氣:氧氣減一,花費時間是 2 (行動需要 1 分鐘,療傷需要 1 分鐘)dp[ TX ][ TY ][ N - 1] = min( dp[ TX ][ TY ][ N - 1 ], dp[ X ][ Y ][ N ] + 2);

到達“ T ”時:更新狀態 dp[ TX ][ TY ][ N ] = min( dp[ TX ][ TY ][ N ], dp[ X ][ Y ][ N ] + 1), (TX, TY, N)不需要再入隊。

AC code:

技術分享圖片
  1 #include <cstdio>
  2 #include <iostream>
  3 #include <queue>
  4 #include <cstring>
  5 #include <algorithm>
  6 #define INF 0x3f3f3f3f
  7 using namespace std;
  8 const int MAXN = 105;
  9 
 10 char g[MAXN][MAXN];          //存原圖
 11 int dp[MAXN][MAXN][10];      //狀態值:當前位置 x y 當前攜帶的氧氣 n
 12 int nx[] = {-1, 0, 1, 0};    //方向數組
 13 int ny[] = {0, 1, 0, -1};
 14 int sx, sy, ex, ey;
 15 int N, M;
 16 struct state
 17 {
 18     int x, y, n;
 19     state(int _i = 0, int _j = 0, int _v = 0):x(_i),y(_j),n(_v){}
 20 };
 21 
 22 void solve()
 23 {
 24     dp[sx][sy][0] = 0;   //dp邊界
 25     //BFS
 26     queue<state> Q;
 27     Q.push(state(sx, sy, 0));
 28     state cur;          //當前狀態
 29     int tx, ty;         //下一個坐標
 30     while(!Q.empty()){
 31         cur = Q.front(); Q.pop();
 32         //printf("curx:%d cury:%d\n", cur.x, cur.y);
 33         for(int k = 0; k < 4; ++k){     //上下左右四個方向
 34             tx = cur.x + nx[k];
 35             ty = cur.y + ny[k];
 36             if(tx < 1 || ty < 1 || tx > N || ty > M) continue;  //超出地圖範圍
 37 
 38             if(g[tx][ty] == S || g[tx][ty] == .){           //起點或者平地
 39 
 40                 if(dp[tx][ty][cur.n] > dp[cur.x][cur.y][cur.n] + 1){
 41                     dp[tx][ty][cur.n] = dp[cur.x][cur.y][cur.n] + 1;
 42                     Q.push(state(tx, ty, cur.n));
 43                     //printf("%c tx:%d ty:%d cnt:%d\n", g[tx][ty], tx, ty, cur.n);
 44                 }
 45             }
 46             else if(g[tx][ty] == T){                          //終點
 47                 //printf("%c\n", g[tx][ty]);
 48                 if(dp[tx][ty][cur.n] > dp[cur.x][cur.y][cur.n]+1)
 49                     dp[tx][ty][cur.n] = dp[cur.x][cur.y][cur.n]+1;
 50             }
 51             else if(g[tx][ty] == P){                          //加速藥丸
 52                 //printf("%c tx:%d ty:%d curx:%d cury:%d\nt:%d cur:%d\n", g[tx][ty], tx, ty, cur.x, cur.y, dp[tx][ty][cur.n], dp[cur.x][cur.y][cur.n]);
 53                 if(dp[tx][ty][cur.n] > dp[cur.x][cur.y][cur.n]){
 54                     dp[tx][ty][cur.n] = dp[cur.x][cur.y][cur.n];
 55                     Q.push(state(tx, ty, cur.n));
 56                     //printf("%c tx:%d ty:%d cnt:%d\n", g[tx][ty], tx, ty, cur.n);
 57                 }
 58             }
 59             else if(g[tx][ty] == B){                          //氧氣
 60 
 61                 if(cur.n < 5 && dp[tx][ty][cur.n+1] > dp[cur.x][cur.y][cur.n] + 1){
 62                     dp[tx][ty][cur.n+1] = dp[cur.x][cur.y][cur.n]+1;
 63                     Q.push(state(tx, ty, (cur.n+1)));
 64                     //printf("%c tx:%d ty:%d cnt:%d\n", g[tx][ty], tx, ty, cur.n+1);
 65                 }
 66                 else if(cur.n == 5 && dp[tx][ty][cur.n] > dp[cur.x][cur.y][cur.n] + 1){
 67                     dp[tx][ty][cur.n] = dp[cur.x][cur.y][cur.n]+1;
 68                     Q.push(state(tx, ty, cur.n));
 69                     //printf("%c tx:%d ty:%d cnt:%d\n", g[tx][ty], tx, ty, cur.n);
 70                 }
 71             }
 72             else if(g[tx][ty] == #){                          //毒氣
 73 
 74                 if(cur.n > 0 && dp[tx][ty][cur.n-1] > dp[cur.x][cur.y][cur.n] + 2){
 75                     dp[tx][ty][cur.n-1] = dp[cur.x][cur.y][cur.n] + 2;
 76                     Q.push(state(tx, ty, (cur.n-1)));
 77                     //printf("%c tx:%d ty:%d cnt:%d\n", g[tx][ty], tx, ty, cur.n-1);
 78                 }
 79             }
 80         }
 81     }
 82     int ans = INF;
 83     for(int i = 0; i <= 5; i++){
 84         //printf("%d\n", dp[ex][ey][i]);
 85         ans = min(ans, dp[ex][ey][i]);
 86     }
 87     if(ans >= INF) printf("-1\n");
 88     else printf("%d\n", ans);
 89 }
 90 
 91 int main()
 92 {
 93     while(~scanf("%d%d", &N, &M) && N && M){
 94         for(int i = 1; i <= N; i++){
 95             scanf("%s", g[i]+1);
 96             g[i][0] = !;
 97             for(int j = 1; j <= M; j++){
 98                 if(g[i][j] == S) sx = i, sy = j;
 99                 else if(g[i][j] == T) ex = i, ey = j;
100                 for(int t = 0; t <= 5; t++) dp[i][j][t] = INF;  //初始化
101             }
102         }
103         //see see
104         //printf("ed:%d %d\n", ex, ey);
105         /*for(int i  = 1; i <= N; i++){
106             for(int j = 1; j <= M; j++){
107                 printf("%c", g[i][j]);
108             }
109             puts("");
110         }*/
111         solve();
112     }
113     return 0;
114 }
View Code

二、優先隊列搜索(師兄解法,學習ing)

AC code:

技術分享圖片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int maxN = 123;
  4 const int inf = 1e9 + 7;
  5 char G[maxN][maxN];
  6 int times[maxN][maxN][6];
  7 int n, m, sx, sy, ex, ey, ans;
  8 int debug = 0;
  9 int dir[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
 10 void dfs(int x, int y, int t, int o) {
 11 
 12     times[x][y][o] = t;
 13 //    printf("x:%d y:%d t:%d o:%d\n", x, y, t, o);
 14     if(x == ex && y == ey) {
 15         ans = min(ans, t);
 16         return;
 17     }
 18 
 19     for(int d = 0; d < 4; d++) {
 20         int tx = x + dir[d][0];
 21         int ty = y + dir[d][1];
 22         if(tx < 0 || tx >= n || ty < 0 || ty >= m) //越界
 23             continue;
 24 
 25 
 26         if(G[tx][ty] == #) {
 27             if(o == 0) {
 28                 continue;
 29             } else if(times[tx][ty][o] > t + 2) {
 30                 dfs(tx, ty, t + 2, o - 1);
 31             }
 32         } else if(G[tx][ty] == P && times[tx][ty][o] > t) {
 33             dfs(tx, ty, t, o);
 34         } else if(G[tx][ty] == B && o < 5 && times[tx][ty][o + 1] > t + 1) {
 35             dfs(tx, ty, t + 1, o + 1);
 36         } else if(times[tx][ty][o] > t + 1) {
 37             dfs(tx, ty, t + 1, o);
 38         }
 39     }
 40 }
 41 struct node {
 42     int x, y, t, o;
 43     bool operator < (const node& p) const {
 44         return t > p.t;
 45     }
 46 };
 47 void bfs() {
 48     node t = (node) {
 49         sx, sy, 0, 0
 50     };
 51     times[sx][sy][0] = 0;
 52     priority_queue<node> q;
 53     q.push(t);
 54     while(!q.empty()) {
 55         node u = q.top();
 56         q.pop();
 57         int x = u.x, y = u.y, o = u.o, t = u.t;
 58 //        printf("%d %d %d %d\n", x, y, t , o);
 59 
 60         if(x == ex && y == ey) {
 61             ans = min(ans, t);
 62             return;
 63         }
 64         for(int d = 0; d < 4; d++) {
 65             int tx = x + dir[d][0];
 66             int ty = y + dir[d][1];
 67             if(tx < 0 || tx >= n || ty < 0 || ty >= m) //越界
 68                 continue;
 69 
 70 
 71             if(G[tx][ty] == #) {
 72                 if(o == 0) {
 73                     continue;
 74                 } else if(times[tx][ty][o-1] > t + 2) {
 75 
 76                     q.push((node) {
 77                         tx,ty,t+2,o-1
 78                     });
 79 
 80                     times[tx][ty][o-1] = t + 2;
 81                 }
 82             } else if(G[tx][ty] == P && times[tx][ty][o] > t) {
 83 
 84                 q.push((node) {
 85                     tx,ty,t,o
 86                 });
 87 
 88                 times[tx][ty][o] = t;
 89             } else if(G[tx][ty] == B && o < 5 && times[tx][ty][o + 1] > t + 1) {
 90 
 91                 q.push((node) {
 92                     tx,ty,t+1,o+1
 93                 });
 94 
 95                 times[tx][ty][o + 1] = t + 1;
 96             } else if(times[tx][ty][o] > t + 1) {
 97 
 98                 q.push((node) {
 99                     tx,ty,t+1,o
100                 });
101 
102                 times[tx][ty][o] = t + 1;
103             }
104         }
105     }
106 }
107 int main() {
108 
109 //    freopen("1.txt","r", stdin);
110 //    freopen("2.txt", "w", stdout);
111     while(~scanf("%d %d", &n, &m)) {
112         if(n == 0)
113             break;
114         for(int i = 0; i < maxN; i++)
115             for(int j = 0; j < maxN; j++)
116                 for(int k = 0 ; k <= 5; k++)
117                     times[i][j][k] = inf;
118         for(int i = 0; i < n; i++) {
119             scanf("%s", G[i]);
120         }
121         for(int i = 0; i < n; i++) {
122             for(int j = 0; j < m; j++) {
123 //                printf("%c", G[i][j]);
124                 if(G[i][j] == S)
125                     sx = i, sy = j;
126                 if(G[i][j] == T)
127                     ex = i, ey = j;
128             }
129 //            puts("");
130         }
131 
132         ans = inf;
133 //        dfs(sx, sy, 0, 0);
134         bfs();
135         if(ans == inf) {
136             printf("-1\n");
137         } else {
138             printf("%d\n", ans);
139         }
140     }
141     return 0;
142 }
View Code

ACM/ICPC 2018亞洲區預選賽北京賽站網絡賽 A、Saving Tang Monk II 【狀態搜索】