ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 A、Saving Tang Monk II 【状态搜索】
任意门:http://hihocoder.com/problemset/problem/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.
输入
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:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
二、优先队列搜索(师兄解法,学习ing)
AC code:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }