# APCS實作題2020年10月第2題:人口遷移
> 日期:2023年9月12日
> 作者:王一哲
> 題目來源:109年10月實作題
> [ZeroJudge 題目連結](https://zerojudge.tw/ShowProblem?problemid=f313)
<br />
## 題目
### 問題描述
$R \times C$ 的平面上有一些城市,每天每個城市會向每個它相鄰的城市遷移 $\frac{人數}{k}$ 個人(整數除法,無條件捨去),請模擬出 $m$ 天之後的結果,輸出人數最少及最多的城市人數。城市人數若為 $-1$ 則代表該位置並非城市,不能由任何城市遷移至此。
下圖是第一筆範例測資模擬的結果
<img height="50%" width="50%" src="https://imgur.com/jdHDCz8.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<br />
### 輸入格式
輸入的第一行包含四個正整數
$$
R, C, k, m ~(1 \leq R,~ m \leq 50,~ 4 \leq k \leq 50)
$$
接下來包含 $R$ 行,每行包含 $C$ 個整數,對於第 $i$ 行的第 $j$ 個整數 $a_{i,j} ~(-1 \leq a_{i, j} \leq 100)$ ,如果是 $-1$ 表示這個座標沒有城市,否則表示這個座標的城市人數數量,保證是非負整數。
配分
- 20%:$R=1, m=1$
- 30%:$R=1$
- 50%:無其他限制
<br />
### 輸出格式
第一行,輸出在 $m$ 天之後,人數最少的城市的人數。
第二行,輸出在 $m$ 天之後,人數最多的城市的人數。
<br />
### 範例:輸入
```
2 3 4 1
10 2 -1
5 -1 2
```
### 範例:正確輸出
```
2
7
```
<br />
## Python 程式碼
於 ZeroJudge 測試結果,最長運算時間約為 0.9 s,使用記憶體最多約為 3.5 MB,通過測試。
```python=
import sys
R, C, k, m = map(int, input().split()) # 讀取第一行資料
pop, move = [], [[0]*C for _ in range(R)] # pop 儲存各都市人口,move 儲存每天各都市遷往相鄰都市的人數
# 讀取接下來R行資料儲存到 pop
for _ in range(R):
pop.append(list(map(int, input().split())))
# 執行 m 次
for _ in range(m):
# 計算每天各都市遷往相鄰都市的人數
for i in range(R):
for j in range(C):
if pop[i][j] != -1:
move[i][j] = pop[i][j] // k
# 更新各都市的人數
for i in range(R):
for j in range(C):
if pop[i][j] != -1:
if i-1 >= 0:
pop[i][j] += move[i-1][j]
pop[i-1][j] -= move[i-1][j]
if i+1 < R:
pop[i][j] += move[i+1][j]
pop[i+1][j] -= move[i+1][j]
if j-1 >= 0:
pop[i][j] += move[i][j-1]
pop[i][j-1] -= move[i][j-1]
if j+1 < C:
pop[i][j] += move[i][j+1]
pop[i][j+1] -= move[i][j+1]
# 儲存最多、最少人數的變數
maxPop = -sys.maxsize - 1
minPop = sys.maxsize
# 找出各都市中最多、最少的人數
for i in range(R):
for j in range(C):
if pop[i][j] != -1:
maxPop = max(maxPop, pop[i][j])
minPop = min(minPop, pop[i][j])
# 印出答案
print(minPop)
print(maxPop)
```
<br /><br />
## C++ 程式碼
於 ZeroJudge 測試結果,最長運算時間約為 5 ms,使用記憶體最多約為 344 kB,通過測試。
```cpp=
#include <iostream>
#include <limits.h>
#include <algorithm>
using namespace std;
int main() {
int R, C, k, m;
cin >> R >> C >> k >> m; // 讀取第一行資料
int pop[R][C], move[R][C]; // pop 儲存各都市人口,move 儲存每天各都市遷往相鄰都市的人數
// 將 move 所有資料都設定為0
for(int i=0; i<R; i++) {
for(int j=0; j<C; j++) {
move[i][j] = 0;
}
}
// 讀取接下來R行資料儲存到 pop
for(int i=0; i<R; i++) {
for(int j=0; j<C; j++) {
cin >> pop[i][j];
}
}
// 執行 m 次
for(int x=0; x<m; x++) {
// 計算每天各都市遷往相鄰都市的人數
for(int i=0; i<R; i++) {
for(int j=0; j<C; j++) {
if (pop[i][j] != -1) {
move[i][j] = pop[i][j] / k;
}
}
}
// 更新各都市的人數
for(int i=0; i<R; i++) {
for(int j=0; j<C; j++) {
if (pop[i][j] != -1) {
if (i-1 >= 0) {
pop[i][j] += move[i-1][j];
pop[i-1][j] -= move[i-1][j];
}
if (i+1 < R) {
pop[i][j] += move[i+1][j];
pop[i+1][j] -= move[i+1][j];
}
if (j-1 >= 0) {
pop[i][j] += move[i][j-1];
pop[i][j-1] -= move[i][j-1];
}
if (j+1 < C) {
pop[i][j] += move[i][j+1];
pop[i][j+1] -= move[i][j+1];
}
}
}
}
}
// 儲存最多、最少人數的變數
int maxPop = INT_MIN;
int minPop = INT_MAX;
// 找出各都市中最多、最少的人數
for(int i=0; i<R; i++) {
for(int j=0; j<C; j++) {
if (pop[i][j] != -1) {
maxPop = max(maxPop, pop[i][j]);
minPop = min(minPop, pop[i][j]);
}
}
}
// 印出答案
cout << minPop << endl;
cout << maxPop << endl;
return 0;
}
```
<br /><br />
---
###### tags:`APCS`、`Python`、`C++`