给定一组不同大小的n
和s
个整数,但从0
到s_i
的正数为正数。在这里定义一个好的总和为a_1 + a_2 + ... + a_s = n
。当你从它的相应集合a_i
中获取每个s_i
个元素时,计算存在多少总和。
我尝试生成任何可能的方法并省略那些可省略的方法,例如当你有s=3
,n=1
时,你会得到集合s_0={0,1}
,{{1} },s_1={0,1,2,3}
,然后您可以省略对s_2={0,1,2}
总和的检查,因为0 + 0 + a_3
不会足够大。
我已经为每个可能的序列应用了正常子集和的动态编程解决方案,但是,我得到的结果比我应该的要大得多,而且速度也很慢。
我可以在这里申请哪些好的算法吗?
答案 0 :(得分:1)
你可以通过使用两个字典(数组也可以工作,但字典更好)来实现经典子集求和解的微小变化:
dp[i] = dictionary of sums we can obtain using the first i sets and their counts
dp[0, <elements in s[0]>] = 1
for i = 1 to s - 1:
for each element x in dp[i - 1]:
for each element k in s[i]:
dp[i, x + k] += dp[i - 1, x]
复杂性将会非常大,但我认为没有太多可以做到的减少它。它应该工作。
你只能在内存中保留两个词典,因为你只需要当前和以前的词典。
Python代码:
def solve(s, n):
dp = [dict()] * len(s)
for k in s[0]:
dp[0][k] = 1
for i in range(1, len(s)):
dp[i] = dict()
for x in dp[i - 1]:
for k in s[i]:
if x + k in dp[i]:
dp[i][x + k] += dp[i - 1][x]
else:
dp[i][x + k] = dp[i - 1][x]
return dp[len(s) - 1][n]
print(solve([[0,1,2],[0,1,2]], 3)) # prints 2
print(solve([[0,1,2],[0,1,2,3,4],[0,1,2,3,4]], 5)) # prints 13