TOJ 449 題目 https://toj.tfcis.org/oj/pro/449/
給一張迷宮的地圖,其中包含障礙物、門、鑰匙、起點、終點
每個門都需要有相對應的鑰匙才可以打開,而一把鑰匙可以無限次使用 地圖可能有多終點
每次可以選擇上下左右一個方向前進,請問最少需要花多少的步驟走到終點
想法 因為要找的是最少步驟,因此可以想到用 BFS 來解
現在所擁有的鑰匙會影響到未來發展,因此每次需要考慮到當前有哪些鑰匙
因此我們的狀態就包含了 當前座標 以及 擁有的鑰匙
我們可以使用 bit 的方式去記錄每個鑰匙是否已經擁有
每次走到門就檢查該 bit 是否是 1
Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 #include <iostream> using namespace std ;int n, m, ans, start_x, start_y;int dx[] = {-1 , 0 , 0 , 1 };int dy[] = {0 , -1 , 1 , 0 };int key_num[26 ], dis[105 ][105 ][50 ];int que[10010 ][3 ];string keys="RGBY" ;char arr[105 ][105 ];bool vis[105 ][105 ][50 ];int BFS () { que[0 ][0 ] = start_x; que[0 ][1 ] = start_y; que[0 ][2 ] = 0 ; dis[start_x][start_y][0 ] = 0 ; vis[start_x][start_y][0 ] = true ; for (int head=0 , tail=1 , x, y, key, nx, ny, nkey ; head<tail ; head++){ x = que[head][0 ]; y = que[head][1 ]; key = que[head][2 ]; if (arr[x][y] == 'X' ){ return dis[x][y][key]; } for (int i=0 ; i<4 ; i++){ nx = x + dx[i]; ny = y + dy[i]; nkey = key; if (nx<0 || nx>=n || ny<0 || ny>=m || arr[nx][ny] == '#' ) continue ; if (arr[nx][ny] == 'R' || arr[nx][ny] == 'G' || arr[nx][ny] == 'B' || arr[nx][ny] == 'Y' ){ if ((key & (1 <<key_num[arr[nx][ny]-'A' ])) == 0 ){ continue ; } } else if (arr[nx][ny] == 'r' || arr[nx][ny] == 'g' || arr[nx][ny] == 'b' || arr[nx][ny] == 'y' ){ nkey = (key | (1 <<key_num[arr[nx][ny]-'a' ])); } if (!vis[nx][ny][nkey]){ vis[nx][ny][nkey] = true ; que[tail][0 ] = nx; que[tail][1 ] = ny; que[tail][2 ] = nkey; dis[nx][ny][nkey] = dis[x][y][key] + 1 ; tail++; } } } return -1 ; } int main () { for (int i=0 ; i<keys.size() ; i++){ key_num[keys[i]-'A' ] = i; } while (cin >>n>>m){ for (int i=0 ; i<n ; i++){ for (int j=0 ; j<m ; j++){ for (int k=0 ; k<50 ; k++){ vis[i][j][k] = false ; } cin >>arr[i][j]; if (arr[i][j] == '*' ){ start_x = i; start_y = j; } } } ans = BFS(); if (ans == -1 ){ cout <<"The poor student is trapped!\n" ; } else { cout <<"Escape possible in " <<ans<<" steps.\n" ; } } return 0 ; }
時間複雜度分析 每筆測資輸入時間複雜度為 $O(nm)$
每筆測資 BFS 時間複雜度為 狀態數 $\times$ 操作的數量 $= (2^4nm) \times(4)$ 大約為 $O(nm)$
每筆測資總時間複雜度為 $O(nm)$