問題
D – 高橋くんの苦悩
回答
defaultdict
defaultdict を使ってみましたが、残念ながらTLEでした。
import collections W = int(input()) N, K = map(int, input().split()) AB = [list(map(int, input().split())) for _ in range(N)] dp = collections.defaultdict(int) def dfs(used_w, used_n, now): """ used_w 今まで選んだ合計幅 used_n 今まで選んだ合計数 now 今調べる番号 """ # メモ化再帰 if '{}_{}_{}'.format(used_w, used_n, now) in dp.keys(): return dp['{}_{}_{}'.format(used_w, used_n, now)] # 終了条件 if now == N: dp['{}_{}_{}'.format(used_w, used_n, now)] = 0 return 0 if used_w >= W or used_n >= K: dp['{}_{}_{}'.format(used_w, used_n, now)] = dfs(used_w, used_n, now+1) return dfs(used_w, used_n, now+1) # 終了条件を満たさない場合 a = AB[now][0] # 幅 b = AB[now][1] # 重要度 # 更新できる場合 if used_w + a <= W and used_n + 1 <= K: val_used = dfs(used_w + a, used_n + 1, now+1) + b val_not_used = dfs(used_w, used_n, now+1) dp['{}_{}_{}'.format(used_w, used_n, now)] = max(val_used, val_not_used) return max(val_used, val_not_used) # 更新できない場合 dp['{}_{}_{}'.format(used_w, used_n, now)] = dfs(used_w, used_n, now+1) return dfs(used_w, used_n, now+1) print(dfs(0, 0, 0))
リスト
DPの配列にリストを使ってみます。
Python では TLE、PyPy では MLE でした。
W = int(input()) N, K = map(int, input().split()) AB = [list(map(int, input().split())) for _ in range(N)] dp = [[[-1]*(N+1) for _ in range(K+1)] for _ in range(W+1)] def dfs(used_w, used_n, now): """ used_w 今まで選んだ合計幅 used_n 今まで選んだ合計数 now 今調べる番号 """ # メモ化再帰 if dp[used_w][used_n][now] >= 0: return dp[used_w][used_n][now] # 終了条件 if now == N: dp[used_w][used_n][now] = 0 return dp[used_w][used_n][now] if used_w >= W or used_n >= K: dp[used_w][used_n][now] = dfs(used_w, used_n, now+1) return dp[used_w][used_n][now] # 終了条件を満たさない場合 a = AB[now][0] # 幅 b = AB[now][1] # 重要度 # 更新できる場合 if used_w + a <= W and used_n + 1 <= K: val_used = dfs(used_w + a, used_n + 1, now+1) + b val_not_used = dfs(used_w, used_n, now+1) dp[used_w][used_n][now] = max(val_used, val_not_used) return dp[used_w][used_n][now] # 更新できない場合 dp[used_w][used_n][now] = dfs(used_w, used_n, now+1) return dp[used_w][used_n][now] print(dfs(0, 0, 0))
lru_cache
@functools.lru_cache
(user_function) でメモ化再帰を行ってみますが、残念ながらTLE。
from functools import lru_cache W = int(input()) N, K = map(int, input().split()) AB = [list(map(int, input().split())) for _ in range(N)] @lru_cache(maxsize=2**30) def dfs(used_w, used_n, now): """ used_w 今まで選んだ合計幅 used_n 今まで選んだ合計数 now 今調べる番号 """ # 終了条件 if now == N: return 0 if used_w >= W or used_n >= K: return dfs(used_w, used_n, now+1) # 終了条件を満たさない場合 a = AB[now][0] # 幅 b = AB[now][1] # 重要度 # 更新できる場合 if used_w + a <= W and used_n + 1 <= K: val_used = dfs(used_w + a, used_n + 1, now+1) + b val_not_used = dfs(used_w, used_n, now+1) return max(val_used, val_not_used) # 更新できない場合 return dfs(used_w, used_n, now+1) print(dfs(0, 0, 0))
DPにリストを使って PyPy で回したのがMLEで一番惜しかったので、これを array
を使うことでメモリを節約して PyPy で回してみると、AC でした。
import array W = int(input()) N, K = map(int, input().split()) AB = [list(map(int, input().split())) for _ in range(N)] dp = [[array.array('i', [-1]*(N+1)) for _ in range(K+1)] for _ in range(W+1)] def dfs(used_w, used_n, now): """ used_w 今まで選んだ合計幅 used_n 今まで選んだ合計数 now 今調べる番号 """ # メモ化再帰 if dp[used_w][used_n][now] >= 0: return dp[used_w][used_n][now] # 終了条件 if now == N: dp[used_w][used_n][now] = 0 return dp[used_w][used_n][now] if used_w >= W or used_n >= K: dp[used_w][used_n][now] = dfs(used_w, used_n, now+1) return dp[used_w][used_n][now] # 終了条件を満たさない場合 a = AB[now][0] # 幅 b = AB[now][1] # 重要度 # 更新できる場合 if used_w + a <= W and used_n + 1 <= K: val_used = dfs(used_w + a, used_n + 1, now+1) + b val_not_used = dfs(used_w, used_n, now+1) dp[used_w][used_n][now] = max(val_used, val_not_used) return dp[used_w][used_n][now] # 更新できない場合 dp[used_w][used_n][now] = dfs(used_w, used_n, now+1) return dp[used_w][used_n][now] print(dfs(0, 0, 0))