---
# System prepended metadata

title: APCS 2023/10/22 python題解

---

# APCS 2023/10/22 python題解

## 1. 機械鼠

https://zerojudge.tw/ShowProblem?problemid=m370

- 利用filter函數找出大於x的食物個數,再判斷往左或往右移動可以吃到更多食物

```python
# 輸入x為老鼠起始位置,n為食物數量,l為食物位置  
x, n = map(int, input().split())
l = list(map(int, input().split()))

# 使用filter找出大於x的食物個數  
temp = len(list(filter(lambda i: i>x, l)))  

# 判斷往左或往右可以吃到更多食物
if temp > n // 2:
  print(temp, max(l)) # 往右吃更多  
else:
  print(n - temp, min(l)) # 往左吃更多
```

## 2. 卡牌遊戲

https://zerojudge.tw/ShowProblem?problemid=m371  

- 記錄每個數字出現位置,判斷可以消除的組合並累加分數

```python
from sys import stdin
e = stdin.readline

# 輸入表格大小 
m, n = map(int, e().split())

# 建立表格  
l = [list(map(int, e().split())) for _ in range(m)]

# 記錄每個數字出現位置
pos = {}  
for i in range(m):
  for j in range(n):
    k = l[i][j]
    if k not in pos:
      pos[k] = []
    if pos[k]:
      x, y = pos[k][0]
      # 判斷是否可以相互消除
      if i != x and j != y:  
        del pos[k]
        continue
    pos[k].append((i, j))
        
# 檢查每個數字的兩個位置是否可以相互消除  
# 如果可以就刪除位置記錄並累加分數
ans = 0
while True:
  for k in pos:
    s, t = pos[k]  
    a, b = s
    c, d = t
    if a == c:
      # 判斷中間是否有阻礙
      for i in range(b+1, d):
        if l[a][i] >= 0: break
      else:
        ans += k
        l[a][b] = -1
        l[c][d] = -1
        del pos[k]
        break
    else:
      for i in range(a+1, c):
        if l[i][b] >= 0: break
      else:
        ans += k
        l[a][b] = -1
        l[c][d] = -1
        del pos[k]
        break
  else: break
        
print(ans)
```

## 3. 搬家

https://zerojudge.tw/ShowProblem?problemid=m372

- DFS搜尋每個連通塊大小並記錄最大值

```python
from sys import stdin
def e(): return stdin.readline().strip()

# 定義水管方向對應表
T = {"F":(0, 1, 0, 1),
     "H":(0, 0, 1, 1),
     "7":(0, 1, 1, 0),
     "I":(1, 1, 0, 0),
     "X":(1, 1, 1, 1),
     "L":(1, 0, 0, 1),
     "J":(1, 0, 1, 0),
     "0":(0, 0, 0, 0)
    }
     
m, n = map(int, e().split())
l = [list(e()+"0") for _ in range(m)] + [["0"]*n]

ans = 0
d = [(-1, 0), (1, 0), (0, -1), (0, 1)]
# DFS搜尋每個連通塊 
for i in range(m):
  for j in range(n):
    if l[i][j] == "0": continue
    stack = [(i, j)]
    c = 0
    while stack:
      i, j = stack.pop()
      if l[i][j] == "0": continue
      t = T[l[i][j]]  
      l[i][j] = "0"
      c += 1
      for idx in range(4):
        if not t[idx]: continue  
        di, dj = d[idx]
        ni, nj = i + di, j + dj
        if T[l[ni][nj]][idx^1]:
          stack.append((ni, nj))
          
    # 記錄最大連通塊大小       
    ans = max(c, ans) 

print(ans)
```

## 4. 投資遊戲

https://zerojudge.tw/ShowProblem?problemid=m373

- 動態規劃計算使用每個金牌的最大收益

```python 
def main():
    from sys import stdin, stdout
    e = stdin.readline

    n, k = map(int, e().split())
    l = list(map(int, e().split()))

    # 建立dp table
    # dp[i][j] = 使用i個金牌,前j天的最大收益
    dp = [[0]*n for i in range(k+1)]
    for i in range(n):
        dp[0][i] = max(dp[0][i-1], 0) + l[i]

    for i in range(1, k+1):
        dp[i][0] = max(0, dp[i-1][0])
        for j in range(1, n):
            # dp轉移式
            dp[i][j] = max(dp[i][j-1] + l[j], dp[i-1][j-1])
    
    # 輸出使用所有金牌的最大收益 
    stdout.write(str(max(dp[-1]+[0])))
main()
```