1. 程式人生 > 其它 >4116:拯救行動,考點:廣搜狀態轉移+剪枝

4116:拯救行動,考點:廣搜狀態轉移+剪枝

原題:http://bailian.openjudge.cn/practice/4116/

描述

公主被惡人抓走,被關押在牢房的某個地方。牢房用N*M (N, M <= 200)的矩陣來表示。矩陣中的每項可以代表道路(@)、牆壁(#)、和守衛(x)。
英勇的騎士(r)決定孤身一人去拯救公主(a)。我們假設拯救成功的表示是“騎士到達了公主所在的位置”。由於在通往公主所在位置的道路中可能遇到守衛,騎士一旦遇到守衛,必須殺死守衛才能繼續前進。
現假設騎士可以向上、下、左、右四個方向移動,每移動一個位置需要1個單位時間,殺死一個守衛需要花費額外的1個單位時間。同時假設騎士足夠強壯,有能力殺死所有的守衛。

給定牢房矩陣,公主、騎士和守衛在矩陣中的位置,請你計算拯救行動成功需要花費最短時間。

輸入

第一行為一個整數S,表示輸入的資料的組數(多組輸入)
隨後有S組資料,每組資料按如下格式輸入
1、兩個整數代表N和M, (N, M <= 200).
2、隨後N行,每行有M個字元。"@"代表道路,"a"代表公主,"r"代表騎士,"x"代表守衛, "#"代表牆壁。

輸出

如果拯救行動成功,輸出一個整數,表示行動的最短時間。
如果不可能成功,輸出"Impossible"

樣例輸入

2
7 8
#@#####@
#@a#@@r@
#@@#x@@@
@@#@@#@#
#@@@##@@
@#@@@@@@
@@@@@@@@ 
13 40
@x@@##x@#x@x#xxxx##@#x@x@@#x#@#x#@@x@#@x
xx###x@x#@@##xx@@@#@x@@#x@xxx@@#x@#x@@x@
#@x#@x#x#@@##@@x#@xx#xxx@@x##@@@#@x@@x@x
@##x@@@x#xx#@@#xxxx#@@x@x@#@x@@@x@#@#x@#
@#xxxxx##@@x##x@xxx@@#x@x####@@@x#x##@#@
#xxx#@#x##xxxx@@#xx@@@x@xxx#@#xxx@x#####
#x@xxxx#@x@@@@##@x#xx#xxx@#xx#@#####x#@x
xx##@#@x##x##x#@x#@a#xx@##@#@##xx@#@@x@x
x#x#@x@#x#@##@xrx@x#xxxx@##x##xx#@#x@xx@
#x@@#@###x##x@x#@@#@@x@x@@xx@@@@##@@x@@x
x#xx@x###@xxx#@#x#@@###@#@##@x#@x@#@@#@@
#@#x@x#x#x###@x@@xxx####x@x##@x####xx#@x
#x#@x#x######@@#x@#xxxx#xx@@@#xx#x#####@

樣例輸出

13
7

解法

思路:廣搜,用一個struct記錄到一個點時的狀態。

struct point {
    int x;
    int y;
    int min;
    bool beated;
    point(int inx,int iny,int m,bool b=false):x(inx),y(iny),min(m),beated(b){}
};

beated表示是否已經打敗守衛,如果有守衛而且還沒有打敗,那麼只能擴展出一個狀態就是打敗守衛,時間數加一。如果沒有守衛就像四周擴充套件,去重保證不走到重複的點。

打敗守衛後的就跟普通道路一樣。

類似上圖,只是我做了一點小變形。

程式碼如下:

 1 #include <iostream>
 2 #include <queue>
 3 #include <cstring>
 4 #define INF 1<<30
 5 using namespace std;
 6 struct point {
 7     int x;
 8     int y;
 9     int min;
10     bool beated;
11     point(int inx,int iny,int m,bool b=false):x(inx),y(iny),min(m),beated(b){}
12 };
13 char G[205][205];
14 int dx[4] = { -1,1,0,0 };
15 int dy[4] = { 0,0,-1,1 };
16 bool visited[205][205];
17 int main()
18 {
19     int S;
20     cin >> S;
21     while (S--) {
22         memset(visited, 0, sizeof(visited));
23         memset(G, '0', sizeof(G));
24         int N, M;
25         int result = INF;
26         queue<point>myqueue;
27         cin >> N >> M;
28         for (int i = 0; i < N; i++)
29             for (int j = 0; j < M; j++) {
30                 cin >> G[i][j];
31                 if (G[i][j] == 'r') {
32                     myqueue.push(point(i, j, 0));
33                     visited[i][j] = 1;
34                 }
35             }
36         while (!myqueue.empty()) {
37             point top = myqueue.front();
38             myqueue.pop();
39             if (G[top.x][top.y] == 'a') {
40                 if (top.min < result)
41                     result = top.min;
42                 continue;
43             }
44             if (top.min + 1 >= result)
45                 continue;
46             if (G[top.x][top.y] == 'x'&&top.beated == false)
47             {
48                 myqueue.push(point(top.x, top.y, top.min + 1, true));
49                 continue;
50             }
51             for (int i = 0; i < 4; i++) {
52                 int tx = top.x + dx[i];
53                 int ty = top.y + dy[i];
54                 if (tx < 0 || tx >= N || ty < 0 || ty >= M)
55                     continue;
56                 if (G[tx][ty] == '#')
57                     continue;
58                 if (visited[tx][ty])
59                     continue;
60                 visited[tx][ty] = 1;
61                 myqueue.push(point(tx, ty, top.min + 1));
62             }
63         }
64         if (result == INF)
65             cout << "Impossible" << endl;
66         else
67             cout << result << endl;
68     }
69     return 0;
70             
71 }