Pythonで理解する蟻本「2-3 個数制限なしナップサック問題」(p.58)
この記事は「プログラミングコンテストチャレンジブック第2版」(蟻本)の
「2-3 個数制限なしナップサック問題」(p.58)
のコードをPythonで書き直したものとなっています。
入力
入力例
3 7
3 4 2
4 5 3
解答
三重ループによる解法(O(nW^2))
MAX_N = 100
MAX_W = 10000
# 入力
n, W = map(int,input().split())
w = list(map(int,input().split()))
v = list(map(int,input().split()))
dp = [[0] * (MAX_W + 1) for _ in range(MAX_N + 1)] # DPテーブル
for i in range(n):
for j in range(W + 1):
k = 0
while k * w[i] <= j:
dp[i + 1][j] = max(dp[i + 1][j], dp[i][j - k * w[i]] + k * v[i])
k += 1
print(dp[n][W])
二重ループによる解法(O(nW))
MAX_N = 100
MAX_W = 10000
# 入力
n, W = map(int,input().split())
w = list(map(int,input().split()))
v = list(map(int,input().split()))
dp = [[0] * (MAX_W + 1) for _ in range(MAX_N + 1)] # DPテーブル
for i in range(n):
for j in range(W + 1):
if j < w[i]:
dp[i + 1][j] = dp[i][j]
else:
dp[i + 1][j] = max(dp[i][j], dp[i + 1][j - w[i]] + v[i])
print(dp[n][W])
同じ配列を再利用した解法(O(nW))
01ナップサック問題の場合
# 入力
n, W = map(int,input().split())
w = list(map(int,input().split()))
v = list(map(int,input().split()))
MAX_N = 100
MAX_W = 10000
dp = [[0] * (MAX_W + 1) for _ in range(MAX_N + 1)] # dpテーブル
for i in range(n - 1, -1, -1):
for j in range(W + 1):
if j < w[i]:
dp[i][j] = dp[i + 1][j]
else:
dp[i][j] = max(dp[i + 1][j], dp[i + 1][j - w[i]] + v[i])
print(dp[0][W])
iに関するループの向きを順方向に直した動的計画法(O(nW))
# 入力
n, W = map(int,input().split())
w = list(map(int,input().split()))
v = list(map(int,input().split()))
MAX_N = 100
MAX_W = 10000
dp = [[0] * (MAX_W + 1) for _ in range(MAX_N + 1)] # dpテーブル
for i in range(n):
for j in range(W + 1):
if j < w[i]:
dp[i + 1][j] = dp[i][j]
else:
dp[i + 1][j] = max(dp[i][j], dp[i][j - w[i]] + v[i])
print(dp[n][W])
01ナップサック問題の場合
MAX_N = 100
MAX_W = 10000
# 入力
n, W = map(int,input().split())
w = list(map(int,input().split()))
v = list(map(int,input().split()))
dp = [0] * (MAX_W + 1) # DPテーブル
for i in range(n):
for j in range(W, w[i] - 1, -1):
dp[j] = max(dp[j], dp[j - w[i]] + v[i])
print(dp[W])
個数制限なしナップサック問題の場合
MAX_N = 100
MAX_W = 10000
# 入力
n, W = map(int,input().split())
w = list(map(int,input().split()))
v = list(map(int,input().split()))
dp = [0] * (MAX_W + 1) # DPテーブル
for i in range(n):
for j in range(w[i], W + 1):
dp[j] = max(dp[j], dp[j - w[i]] + v[i])
print(dp[W])