SOJ 1135. 飞跃原野

解题技巧:

  1. 求从左上角到右下角的最短时间,可用BFS,一步为一个单位时间。

    BFS中的状态:人所在的行、列和能飞行的距离。

    每步选择的转移有:(i)不飞行到达相邻位置 (ii)使用飞行到达更远的地方。

    判断下一状态是否有效(是否可放入下一次进行BFS队列中)的根据是:下一状态的能量比以往相应位置的“能飞行的距离”充裕,即可以使用更大的“能飞行的距离”来寻找目的地。因为unit在递增。

  2.状态压缩:一个状态包括行、列和能飞行的距离,由于三者均<=100;故能压缩成一个整数。

代码如下:

 1 #include <cstdio>
 2 #include <queue>
 3 using namespace std;
 4 const int maxm = 100;
 5 const int maxn = 100;
 6 
 7 char altas[maxm][maxn + 1];
 8 int max_energy[maxm][maxn];
 9 
10 const int dm = 100000;
11 const int dn = 1000;
12 const int dd = 1;
13 
14 // 0-右,1-左,2-上,3-下
15 int dx[4] = {0, 0, -1, 1};
16 int dy[4] = {1, -1, 0, 0};
17 
18 void init(int m, int n) {
19     for (int i = 0; i < m; ++i)
20         for (int j = 0; j < n; ++j)
21             max_energy[i][j] = -1;
22 }
23 
24 int main() {
25     int m, n, d;
26     while (scanf("%d%d%d", &m, &n, &d) != EOF) {
27         init(m, n); // 初始化
28         for (int i = 0; i < m; ++i) scanf("%s", altas[i]);  // 输入地图
29 
30         if (m == 1 && n == 1) { // 特殊情况判断
31             printf("0\n");
32             continue;
33         }
34         // bfs
35         int start = 0 * dm + 0 * dn + d * dd;
36         max_energy[0][0] = d;   // 初始状态的d最充足
37         queue<int> que; que.push(start);
38         int unit = 0;
39         bool find = false;
40         while (!que.empty() && !find) {
41             ++unit;
42             int size = que.size();
43             while (size-- && !find) {
44                 int state = que.front(); que.pop(); // 获取状态
45                 int r = state / dm; // 状态还原
46                 int c = state % dm / dn;
47                 int e = state % dn;
48 
49                 // 找下一步可走位置
50                 // 先环顾最近的四个方向一圈
51                 for (int i = 0; i < 4 && !find; ++i) {
52                     int next_m = r + dx[i];
53                     int next_n = c + dy[i];
54                     if (0 <= next_m && next_m < m && 0 <= next_n && next_n < n && altas[next_m][next_n] == 'P') {
55                         if (e > max_energy[next_m][next_n]) {   // 后来的如果能量更加充足,可以重新启动该点
56                             max_energy[next_m][next_n] = e;
57                             int next_state = next_m * dm + next_n * dn + e * dd;
58                             que.push(next_state);
59                             if (next_m == m - 1 && next_n == n - 1) find = true;
60                         }
61                     }
62                 }
63                 // 再考虑飞行的可能
64                 // 0-右,1-左,2-上,3-下
65                 for (int i = 0; i < 4 && !find; ++i) {
66                     for (int j = 2; j <= e && !find; ++j) {
67                         int next_m = r + dx[i] * j;
68                         int next_n = c + dy[i] * j;
69                         if (0 <= next_m && next_m < m && 0 <= next_n && next_n < n) {
70                             if (altas[next_m][next_n] == 'P') {
71                                 if (e - j > max_energy[next_m][next_n]) {
72                                     max_energy[next_m][next_n] = e - j;
73                                     int next_state = next_m * dm + next_n * dn + (e - j) * dd;
74                                     que.push(next_state);
75                                     if (next_m == m - 1 && next_n == n - 1) find = true;
76                                 }
77                             }
78                         } else {
79                             break;
80                         }
81                     }
82                 }
83 
84             }
85         }
86 
87         if (find) printf("%d\n", unit);
88         else printf("impossible\n");
89     }
90     return 0;
91 }

 

posted @ 2016-01-09 16:24  MchCyLh  阅读(487)  评论(0编辑  收藏  举报