# APCS實作題2024年6月第2題:電子畫布
> 日期:2024年7月2日
> 作者:王一哲
> 題目來源:2024年6月實作題第2題
> [ZeroJudge 題目連結](https://zerojudge.tw/ShowProblem?problemid=o077)
## 題目
### 問題描述
有一個 $H \times W$ 的電子畫布,一開始數值都是 $0$ 代表未填色,接下來請模擬 $N$ 次畫筆操作。
每次畫筆操作為選一個座標 $(r, c)$ 停留 $t$ 秒,他會將曼哈頓距離 $\leq t$ 的區塊染上顏色 $x$。若有多個顏色重複填到相同區塊,顏色的數值會累加起來。
請輸出 $N$ 次操作後的畫布狀態。
### 輸入說明
第一行輸入三個正整數 $H, W, N ~(1 \leq H, W \leq 20,~ 1 \leq N \leq 100)$。
接下來有 $N$ 行,每一行有四個整數 $r, c, t, x ~(0 \leq r < H,~ 0 \leq c < W,~ 0 \leq t \leq 20,~ 1 \leq x \leq 10)$
。
子題分數:
- 60%:$H=5$。
- 40%:無限制。
<br />
### 輸出格式
輸出畫布做 $N$ 次畫筆操作後的狀態。
<br />
### 範例輸入1
```
1 20 3
0 13 5 7
0 6 4 4
0 13 12 6
```
### 範例輸出1
```
0 6 10 10 10 10 10 10 17 17 17 13 13 13 13 13 13 13 13 6
```
### 範例輸入2
```
6 7 3
3 2 2 1
1 6 1 2
1 3 2 5
```
### 範例輸出2
```
0 0 5 5 5 0 2
0 5 6 5 5 7 2
0 1 6 6 5 0 2
1 1 1 6 1 0 0
0 1 1 1 0 0 0
0 0 1 0 0 0 0
```
<br />
## Python 程式碼
費時最久約為 40 ms,使用記憶體最多約為 3.4 MB,通過測試。
```python=
H, W, N = map(int, input().split()) # 讀取 H, W, N
canvas = [[0]*W for _ in range(H)] # 表示畫布狀態的 H*W 的二維串列
for _ in range(N): # 執行N次
r, c, t, x = map(int, input().split()) # 讀取 r, c, t, x
for nr in range(max(0, r-t), min(H, r+t+1)): # nr 的範圍為 0 或 (r-t) ~ (H-1) 或 (r+t)
for nc in range(max(0, c-t), min(W, c+t+1)): # nc 的範圍為 0 或 (c-t) ~ (W-1) 或 (c+t)
if abs(nr-r) + abs(nc-c) <= t: # 如果 (nr, nc) 與 (r, c) 的曼哈頓距離小於等於 t
canvas[nr][nc] += x # 更新畫布 (nr, nc) 的值
for row in canvas: print(*row) # 利用 for 迴圈與開箱運算子印出答案
```
<br /><br />
## C++ 程式碼
### 寫法1,使用 array
費時最久約為 3 ms,使用記憶體最多約為 324 kB,通過測試。
```cpp=
#include <iostream>
#include <cstring> // for memset
#include <cmath> // for abs
using namespace std;
int main() {
int H, W, N, r, c, t, x;
cin >> H >> W >> N; // 讀取 H, W, N
int canvas[H][W]; // 表示畫布狀態的 H*W 的二維陣列
memset(canvas, 0, sizeof(canvas[0][0])*H*W); // 將 canvas 內容初始化為0
for(int i=0; i<N; i++) { // 執行N次
cin >> r >> c >> t >> x; // 讀取 r, c, t, x
int nri = (r-t > 0) ? (r-t) : 0, nrf = (r+t+1 < H) ? (r+t+1) : H;
int nci = (c-t > 0) ? (c-t) : 0, ncf = (c+t+1 < W) ? (c+t+1) : W;
for(int nr=nri; nr < nrf; nr++) { // nr 的範圍為 0 或 (r-t) ~ (H-1) 或 (r+t)
for(int nc=nci; nc < ncf; nc++) { // nc 的範圍為 0 或 (c-t) ~ (W-1) 或 (c+t)
if (abs(nr-r) + abs(nc-c) <= t) // 如果 (nr, nc) 與 (r, c) 的曼哈頓距離小於等於 t
canvas[nr][nc] += x; // 更新畫布 (nr, nc) 的值
}
}
}
// 印出答案
for(int i=0; i<H; i++)
for(int j=0; j<W; j++)
cout << canvas[i][j] << " \n"[j == W-1];
return 0;
}
```
<br /><br />
### 寫法2,使用 vector 及 algorithm
費時最久約為 3 ms,使用記憶體最多約為 332 kB,通過測試。
```cpp=
#include <iostream>
#include <cmath> // for abs
#include <vector>
#include <algorithm> // for max, min
using namespace std;
int main() {
int H, W, N, r, c, t, x;
cin >> H >> W >> N; // 讀取 H, W, N
vector<vector<int>> canvas (H, vector<int> (W, 0)); // 表示畫布狀態的 H*W 的二維陣列
for(int i=0; i<N; i++) { // 執行N次
cin >> r >> c >> t >> x; // 讀取 r, c, t, x
for(int nr=max(0, r-t); nr < min(H, r+t+1); nr++) { // nr 的範圍為 0 或 (r-t) ~ (H-1) 或 (r+t)
for(int nc=max(0, c-t); nc < min(W, c+t+1); nc++) { // nc 的範圍為 0 或 (c-t) ~ (W-1) 或 (c+t)
if (abs(nr-r) + abs(nc-c) <= t) // 如果 (nr, nc) 與 (r, c) 的曼哈頓距離小於等於 t
canvas[nr][nc] += x; // 更新畫布 (nr, nc) 的值
}
}
}
// 印出答案
for(int i=0; i<H; i++)
for(int j=0; j<W; j++)
cout << canvas[i][j] << " \n"[j == W-1];
return 0;
}
```
<br /><br />
---
###### tags:`APCS`、`Python`、`C++`