###### tags: `APCS` # **f149-炸彈偵測器** ### **題目連結:** [**f149**](https://zerojudge.tw/ShowProblem?problemid=f149) ### **題目解析** 在這個問題中,我們有一個軍事基地正在開發的炸彈偵測器系統。這些偵測器會被放置在一個由R行和C列組成的矩陣中,並以中心位置為中心來檢測周圍的炸彈。偵測器相鄰的格子(八個方向)中如果有其他偵測器存在,則會發生磁場干擾,導致偵測器失靈。需要計算有多少炸彈可以被偵測到,以及有多少炸彈無法被偵測到。 ### **解題方向** 1. 讀取輸入: * 第一行包含兩個整數R和C,表示矩陣的行數和列數。 * 接下來的R行,每行有C個整數,表示矩陣中每個位置的狀態:5表示偵測器,1表示炸彈,0表示空地。 1. 檢查偵測器: * 對於每一個位置,如果是偵測器5,則檢查它周圍的八個格子是否有其他偵測器。如果有,則將該偵測器設為失靈6。 * 如果偵測器周圍沒有其他偵測器,它可以有效工作,檢查周圍是否有炸彈,若有炸彈則計數偵測到的炸彈。 1. 計算結果: * 最後遍歷矩陣,計算未被偵測到的炸彈數量。 ### **程式解析** 導入模組與函數定義 ```python import sys def showmap(m, r, c): for i in range(0, r): for j in range(0, c): print(m[i][j], end=' ') print() ``` * import sys: 導入sys模組以使用標準輸入。 * showmap 函數:這個函數用於打印地圖的當前狀態,接受一個二維列表m和它的行數r與列數c。雖然這個函數在當前程式碼中被註釋掉並未使用,但它對於除錯或顯示地圖狀態很有用。 讀取輸入和初始化地圖 ```python # 讀取行數和列數 s = input() size = [int(i) for i in s.split()] R = size[0] C = size[1] # 初始化地圖矩陣 MAP = [] # 讀取地圖 r = 0 for s in sys.stdin: row = list(map(int, s.split())) MAP.append(row) r += 1 if r >= R: break ``` * 讀取行數和列數: * 使用input()讀取第一行的R和C,表示地圖的行數和列數。 * size = [int(i) for i in s.split()]將讀入的字串分割為整數列表。 * R和C分別表示地圖的行和列。 * 初始化地圖: * MAP = [] 初始化一個空列表來存儲地圖。 * 讀取地圖內容:使用sys.stdin來讀取後續的R行數據,每行分割成整數並附加到MAP中。 * 用for迴圈和sys.stdin來逐行讀取地圖的每一行,直到讀完R行。 初始化偵測器和炸彈計數 ```python detected = 0 undetected = 0 ``` 檢查偵測器的有效性 ```python # 檢查地圖以偵測炸彈 for i in range(0, R): for j in range(0, C): # 檢查是否為偵測器 if MAP[i][j] != 0 and MAP[i][j] != 1: # 檢查周圍八個方向 for m in range(j-1, j+2): for n in range(i-1, i+2): if m >= 0 and m < C and n >= 0 and n < R and not (m == j and n == i): if MAP[n][m] >= 5: # 發現相鄰偵測器 MAP[n][m] = 6 # 標記為失靈 MAP[i][j] = 6 ``` * 雙重迴圈遍歷整個矩陣: * 外層迴圈for i in range(0, R) 遍歷每一行。 * 內層迴圈for j in range(0, C) 遍歷每一列。 * 檢查偵測器: * 如果地圖上位置MAP[i][j]的值不是0(空地)或1(炸彈),即為偵測器。 * 檢查偵測器周圍: * 檢查偵測器周圍的八個格子(用m和n進行偏移)。 * 如果發現其他偵測器(值為5或以上),將當前偵測器標記為失靈6。 * MAP[n][m] = 6將相鄰的偵測器也標記為失靈。 偵測炸彈 ```python if MAP[i][j] == 5: # 如果偵測器沒失靈 for m in range(j-1, j+2): for n in range(i-1, i+2): if m >= 0 and m < C and n >= 0 and n < R: if MAP[n][m] == 1: # 偵測到炸彈 detected += 1 MAP[n][m] = 0 # 標記炸彈為已偵測 ``` * 檢查有效偵測器: * 如果偵測器MAP[i][j]仍然為5(即沒有失靈),則它是有效的。 * 檢測炸彈: * 再次檢查周圍的八個格子。 * 如果發現炸彈(MAP[n][m] == 1),則計數偵測到的炸彈,並將炸彈位置標記為0,表示已被偵測。 計算未偵測炸彈 ```python # 計算未被偵測到的炸彈數量 for i in range(0, R): for j in range(0, C): if MAP[i][j] == 1: undetected += 1 ``` * 遍歷整個地圖: * 再次使用雙重迴圈遍歷矩陣。 * 計算未偵測到的炸彈: * 如果位置MAP[i][j]仍然是1,表示該炸彈未被偵測,將undetected計數加一。 ### **完整程式碼** ```python= import sys def showmap(m, r, c): for i in range(0, r): for j in range(0, c): print(m[i][j], end=' ') print() #start s = input() size = [ int(i) for i in s.split() ] R = size[0] C = size[1] MAP = [] r = 0 for s in sys.stdin: # 把資料丟入list row = list(map(int, s.split())) MAP.append(row) r +=1 if r >= R : break #showmap(MAP, R, C) detected = 0 undetected = 0 #detect mine for i in range(0, R): for j in range(0, C): # check map if MAP[i][j] != 0 and MAP[i][j] != 1: # * * * # * 5 * # * * * for m in range(j-1, (j+1)+1):# 偵測附近八個點是否有「其他偵測器」 for n in range(i-1, (i+1)+1): if m>=0 and m<C and n>=0 and n<R and not (m==j and n==i): # 確保在界限之內,且會跳過MAP[i][j] if MAP[n][m] >=5: #print("find...", n, m) #當偵測器的範圍內包含另一個偵測器時(即,當周圍的八個點中至少有一點的值大於或等於 5),當前的偵測器(MAP[i][j])和該範圍內的其他偵測器的值都會被設置為 6。這代表兩個或多個偵測器之間的信號干擾,導致它們無法正常偵測炸彈。 MAP[n][m] = 6 MAP[i][j] = 6 if MAP[i][j] == 5:# MAP[i][j]還是5就代表範圍內沒有其他偵測器 #print("find detector in ", i, j) # 偵測附近八個點是否有炸彈 for m in range(j-1, (j+1)+1):# 慢慢將偵測到的累加起來 for n in range(i-1, (i+1)+1): if m>=0 and m<C and n>=0 and n<R: if MAP[n][m] == 1: detected += 1 MAP[n][m] = 0 # 偵測到炸彈後將1改為0 # end of if #showmap(MAP, R, C) for i in range(0, R): for j in range(0, C): if MAP[i][j] == 1:# 已偵測的為0,未偵測的就是原來的1 undetected += 1 #showmap(MAP, R, C) print(detected, undetected) ```