ここでは、部分和問題の中で使える数に使用制限があるケースの問題について、 「プログラミングコンテストチャレンジブック(第2版)」(通称:蟻本)の p63 を例に、python3 で実装する方法を紹介します。
蟻本では、DP(動的計画法)で実装しており、 配列dp を再利用することで一次元配列にしていますが、ここでは分かりやすさを優先して、二次元配列で実装しています。
# 入力
n = 3
a = [3, 5, 8]
m = [3, 2, 2]
k = 17
#メモ化テーブル(-1 で初期化)
dp = [ [ -1 for j in range(k + 1)] for _ in range(n+1) ]
#先頭にダミーとして0を代入
dp[0][0] = 0
# 0からkまでの数字について、与えられたaを何個残して作れるか?を配列dpに記述していく
def solve():
for i in range(n):
for j in range(k+1):
# すでに j を作れることが分かっている場合
if dp[i][j] >= 0:
# 全部残せる
dp[i+1][j] = m[i]
# j を作ることができない場合
elif j < a[i] or dp[i+1][j - a[i]] <= 0:
# できないという意の -1 を記述
dp[i+1][j] = -1
# a[i] を1個使えば jを作ることができる場合
else:
# dp[i+1][j - a[i]]の場合に残っていたものから1個引いた値を記述
dp[i+1][j] = dp[i+1][j - a[i]] - 1
if __name__ == '__main__':
solve()
if dp[n][k] >= 0:
print('Yes')
else:
print('No')
以上になります。