ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 ASaving Tang Monk II 状态搜索

Posted ymzjj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 ASaving Tang Monk II 状态搜索相关的知识,希望对你有一定的参考价值。

任意门: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
", 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
", g[tx][ty], tx, ty, cur.n);
 44                 }
 45             }
 46             else if(g[tx][ty] == T){                          //终点
 47                 //printf("%c
", 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
t:%d cur:%d
", 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
", 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
", 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
", 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
", 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
", dp[ex][ey][i]);
 85         ans = min(ans, dp[ex][ey][i]);
 86     }
 87     if(ans >= INF) printf("-1
");
 88     else printf("%d
", 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
", 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
", 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
", 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
");
137         } else {
138             printf("%d
", ans);
139         }
140     }
141     return 0;
142 }
View Code

 

以上是关于ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 ASaving Tang Monk II 状态搜索的主要内容,如果未能解决你的问题,请参考以下文章

ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 ASaving Tang Monk II 状态搜索

ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 A.Saving Tang Monk II(优先队列广搜)

2018亚洲区预选赛北京赛站网络赛 C.Cheat

2018亚洲区预选赛北京赛站网络赛 A.Saving Tang Monk II BFS

2018ACM/ICPC 焦作网络预选赛-A Magic Mirror

2014ACM/ICPC亚洲区北京站题解