###### tags: `APCS`
# **d406-倒水時間**
### **題目連結:** [**d406**](https://zerojudge.tw/ShowProblem?problemid=d406)
### **題目解析**
這個問題模擬了水在具有方向性的網格中的流動。水從地圖的頂端某一個位置開始,根據給定的條件,水可以向下、向左、向右流動,而根據不同的情況,水可能也可以向上流動。我們要計算水流到每個位置的最短時間。
### **解題方向**
1. 建立地圖:
* 使用二維陣列來表示地圖,1 表示有水管(可以通過),0 表示沒有水管(不能通過)。
1. 初始條件:
* 找到地圖的第一行中最先出現 1 的位置,作為水流開始的位置。
1. 使用 BFS 進行擴展:
* 使用廣度優先搜尋(BFS)來模擬水的流動,從起始位置開始,依次擴展到相鄰的格子。
* 在 BFS 中,每個格子都從鄰近的格子中獲得時間標記,這些標記值代表水流到該位置所需的時間。
1. 流動方向控制:
* 根據輸入的參數 S 來決定水是否可以向上流動。若 S = 1,則允許水往上流動;若 S = 2,則不允許。
### **程式解析**
1. 建立資料結構:
* MAP:儲存地圖的水管配置。
* marked:用來標記水流到達每個位置的最短時間,初始值為 0。
1. 尋找起點:
* 從第一行開始搜尋,找到第一個 1 的位置作為水流的起點,並將其放入 BFS 的佇列 Q 中,並標記該位置的時間為 1。
1. BFS 搜尋:
* 從佇列中取出當前位置,依次檢查水是否可以流到左、下、右(以及根據 S 決定是否可以向上)的位置。
* 若可以流動,則將該位置的時間標記為當前時間加一,並將該位置加入佇列中繼續擴展。
1. 輸出結果:
* 輸出每個地圖的最終標記時間。
### **完整程式碼**
```python=
# (0, -1)
# [3]
# (-1, 0)[1] [c] [2] (1, 0)
# [0]
# (0, 1)
#dx = [ 0, 1, 0, -1]
#dy = [ 1, 0, -1, 0]
case=1
while True:
try:
#start
S = int(input())
N, M = map(int, input().split())
MAP = []
for i in range(N):
row = list(map(int, input().split()))
MAP.append(row)
marked = [ [0 for i in range(M)] for j in range(N) ]
# 全為0的二維陣列
#====================================================
r, c = 0, 0
#find the top row
# 目的是要找出起點洞口
while MAP[r][c]==0 :
c+=1
# BFS
Q = [[r, c]]# 起點放入Queue中
marked[r][c] = 1
while len(Q) >0:
now = Q.pop(0)
r = now[0]
c = now[1]
#print(r, c)
# 左
if c-1>=0 :
if MAP[r][c-1] == 1 and marked[r][c-1] ==0:
marked[r][c-1] = marked[r][c]+1
Q.append([r, c-1])
# 下
if r+1<N :
if MAP[r+1][c] == 1 and marked[r+1][c] ==0:
marked[r+1][c] = marked[r][c]+1
Q.append([r+1, c])
# 右
if c+1<M :
if MAP[r][c+1] == 1 and marked[r][c+1] ==0:
marked[r][c+1] = marked[r][c]+1
Q.append([r, c+1])
# 上
if r-1>=0 and S==1:
if MAP[r-1][c] == 1 and marked[r-1][c] == 0:
marked[r-1][c] = marked[r][c]+1
Q.append([r-1, c])
#print(Q)
print("Case %d:" % case)
for i in range(N):
for j in range(M):
print(marked[i][j], end=' ')
print()
case+=1
except:
break
```