# APCS實作題2021年9月第2題:魔王迷宮 > 日期:2023年9月16日 > 作者:王一哲 > 題目來源:110年9月實作題第2題 > [ZeroJudge 題目連結](https://zerojudge.tw/ShowProblem?problemid=g276) <br /> ## 題目 ### 問題描述 在一個 $n \times m$ 的棋盤上有 $k$ 個魔王,一開始第 $i$ 魔王會位在 $(r_i, c_i)$ 的位置上,並且每回合會移動 $(s_i, t_i)$。也就是說,若本來在 $(x, y)$ 位置,經過移動後會跳到 $(x+s_i, y+t_i)$ 位置。 每個魔王都有不同的 $(r, c, s, t)$ 值,每回合每個魔王移動前會在所在位置上放下一顆炸彈,然後才進行移動,而若魔王移動到已經被放有炸彈的位置,炸彈則會被引爆,該位置的魔王和炸彈則消失不見。如果兩個魔王同時踏到同一個炸彈上會一起被炸掉,如果同一位置上有多個炸彈也會被一起引爆。 當魔王移動超出整個棋盤的範圍,則被視為消失。 請計算,當棋盤上沒有任何魔王時,盤面上總共剩下幾格有炸彈? <br /> ### 輸入說明 第一行輸入三個正整數 $n (1 \leq n \leq 100)$、$m (1 \leq m \leq 100)$、$k (1 \leq k \leq 500)$,代表盤面大小為 $n \times m$,上面一開始有 $k$ 個魔王。 接下來有 $k$ 行,第 $i$ 行有四個整數 $r_i, c_i, s_i, t_i ~(0 \leq r < n, 0 \leq c < m)$。 配分 - 50分:$n = 1, r_i = 0, s_i = 0$ - 50分:無其它限制 <br /> ### 輸出說明 輸出當場上沒有魔王的時候剩下幾格有炸彈 <br /> ### 範例一:輸入 ``` 1 6 3 0 0 0 0 0 2 0 -1 0 4 0 2 ``` ### 範例一:正確輸出 ``` 4 ``` <br /> ### 範例二:輸入 ``` 5 5 2 0 0 3 2 0 0 2 3 ``` ### 範例二:正確輸出 ``` 3 ``` <br /> ## Python 程式碼 ### 版本1,使用二維串列儲存地圖上每一格的炸彈數量,會超時 於 ZeroJudge 測試結果,於第15筆測資會超時。 ```python= n, m, k = map(int, input().split()) # 讀取n, m, k num = k # 魔王數量 demons = [] # 魔王初位置、移動步數 for _ in range(k): # 讀取k行的魔王資料 demons.append(list(map(int, input().split()))) bombs = [[0]*m for _ in range(n)] # 儲存地圖上炸彈位置的二維串列 outs = [False]*k # 魔王是否已出局 while num > 0: # 當還有魔王在場上時繼續執行 for i in range(k): # 依序更新每個魔王的狀態 if not outs[i]: # 如果還沒有出局 bombs[demons[i][0]][demons[i][1]] += 1 # 於這個位置留下炸彈 demons[i][0] += demons[i][2] # 更新x座標 demons[i][1] += demons[i][3] # 更新y座標 if demons[i][0] < 0 or demons[i][0] >= n or demons[i][1] < 0 or demons[i][1] >= m: # 如果出界,outs 設定為 True,數量減1 outs[i] = True num -= 1 for x in range(n): # 檢查每一格地圖 for y in range(m): if bombs[x][y] >= 1: # 如果格子上有炸彈 count = 0 # 踩到炸彈的魔王數量 for i in range(k): # 檢查還在場上的魔王是否踩到炸彈 if demons[i][0] == x and demons[i][1] == y and not outs[i]: outs[i] = True # 出局 num -= 1 # 魔王數量減1 count += 1# 踩到炸彈的魔王數量加1 if count >= 1: # 如果有魔王踩到炸彈 bombs[x][y] = 0 # 將這格的炸彈數量歸0 ans = 0 # 有炸彈的格子數量 for bomb in bombs: # 讀取地圖上每一個格子,如果格子中有炸彈將 ans 加1 for b in bomb: if b >= 1: ans += 1 print(ans) # 印出答案 ``` <br /><br /> ### 版本2,當魔王出局或炸彈爆炸時移出串列,會超時 於 ZeroJudge 測試結果,於第16筆測資會超時。 ```python= n, m, k = map(int, input().split()) # 讀取n, m, k num = k # 魔王數量 demons = [] # 魔王初位置、移動步數 for _ in range(k): # 讀取k行的魔王資料 demons.append(list(map(int, input().split()))) bombs = [] # 儲存地圖上炸彈位置的二維串列 while demons: # 當還有魔王在場上時繼續執行 dc = 0 # 於這一輪出局的魔王數量 for i in range(len(demons)): # 依序更新每個魔王的狀態 idx = i - dc # 索引值要扣掉出局的魔王數量 if [demons[idx][0], demons[idx][1]] not in bombs: # 如果這個位置目前沒有炸彈 bombs.append([demons[idx][0], demons[idx][1]]) # 於這個位置留下炸彈 demons[idx][0] += demons[idx][2] # 更新x座標 demons[idx][1] += demons[idx][3] # 更新y座標 if demons[idx][0] < 0 or demons[idx][0] >= n or demons[idx][1] < 0 or demons[idx][1] >= m: # 如果出界 demons.pop(idx) # 移除這個魔王 dc += 1 # 出局數加1 bc = 0 # 於這一輪移除的炸彈數量 for i in range(len(bombs)): # 檢查每一個炸彈的位置 count = 0 # 踩到炸彈的魔王數量 de = 0 # 於這一輪出局的魔王數量 idx = i - bc # 索引值要扣掉移除的炸彈數量 for j in range(len(demons)): # 檢查還在場上的魔王是否踩到炸彈 jdx = j - de # 索引值要扣掉出局的魔王數量 if demons[jdx][0] == bombs[idx][0] and demons[jdx][1] == bombs[idx][1]: # 如果踩到炸彈 demons.pop(jdx) # 移除這個魔王 de += 1 # 出局數加1 count += 1# 踩到炸彈的魔王數量加1 if count >= 1: # 如果有魔王踩到炸彈 bombs.pop(idx) # 刪除這個炸彈 bc += 1 # 移除的炸彈數量 print(len(bombs)) # 印出答案 ``` <br /><br /> ## C++ 程式碼 用 Python 程式碼版本1改寫成 C++ 程式碼,於 ZeroJudge 測試結果,最長運算時間約為 10 ms,使用記憶體最多約為 360 kB,通過測試。 ```cpp= #include <iostream> using namespace std; int main() { int n, m, k; cin >> n >> m >> k; // 讀取n, m, k int num = k; // 魔王數量 int demons[k][4], bombs[n][m]; // 魔王初位置、移動步數,儲存地圖上炸彈位置 bool outs[k] = {false}; // 魔王是否已出局 /* 讀取k行的魔王資料 */ for(int i=0; i<k; i++) { for(int j=0; j<4; j++) { cin >> demons[i][j]; } } /* 地圖上每個格子的炸彈數量 */ for(int i=0; i<n; i++) { for(int j=0; j<m; j++) { bombs[i][j] = 0; } } /* 當還有魔王在場上時繼續執行 */ while(num > 0) { for(int i=0; i<k; i++) { // 依序更新每個魔王的狀態 if (!outs[i]) { // 如果還沒有出局 bombs[demons[i][0]][demons[i][1]]++; // 於這個位置留下炸彈 demons[i][0] += demons[i][2]; // 更新x座標 demons[i][1] += demons[i][3]; // 更新y座標 if (demons[i][0] < 0 || demons[i][0] >= n || demons[i][1] < 0 || demons[i][1] >= m) { // 如果出界,outs 設定為 True,數量減1 outs[i] = true; num--; } } } for(int x=0; x<n; x++) { // 檢查每一格地圖 for(int y=0; y<m; y++) { if (bombs[x][y] >= 1) { // 如果格子上有炸彈 int count = 0; // 踩到炸彈的魔王數量 for(int i=0; i<k; i++) { // 檢查還在場上的魔王是否踩到炸彈 if (demons[i][0] == x && demons[i][1] == y && !outs[i]) { outs[i] = true; // 出局 num--; // 魔王數量減1 count++;// 踩到炸彈的魔王數量加1 } } if (count >= 1) bombs[x][y] = 0; // 如果有魔王踩到炸彈,將這格的炸彈數量歸0 } } } } /* 計算答案 */ int ans = 0; // 有炸彈的格子數量 for(int i=0; i<n; i++) { // 讀取地圖上每一個格子,如果格子中有炸彈將 ans 加1 for(int j=0; j<m; j++) { if (bombs[i][j] >= 1) ans++; } } cout << ans << endl; // 印出答案 return 0; } ``` <br /><br /> --- ###### tags:`APCS`、`Python`、`C++`