简体   繁体   English

使用动态编程查找子集和

[英]Finding subset sum using dynamic programming

I'm practicing Dynamic Programming and I'm struggling with debugging my code. 我正在练习动态编程,我正在努力调试我的代码。 The idea is to find if a sum is possible given a list of numbers. 我们的想法是在给定数字列表的情况下查找是否可以求和。 Here's my code: 这是我的代码:

a = [2,3,7,8,10]
sum = 11
b = list(range(1, sum+1))
m = [[False for z in range(len(b))] for i in range(len(a))]

for i, x in enumerate(b):
    for j, y in enumerate(a):
        if x==y:
            m[j][i]=True
        elif y<x:
            m[j][i] = m[j-1][i]
        else:
            m[j][i] = m[j-1][i] or m[j-i][y-x]

for i, n in enumerate(m):
    print(a[i], n)

And here is the output: 这是输出:

2 [False, True, False, False, False, False, False, False, False, False, False]
3 [False, True, True, False, False, False, False, False, False, False, False]
7 [False, True, True, False, True, True, True, False, False, False, False]
8 [False, True, True, False, True, True, True, True, False, False, False]
10 [False, True, True, False, True, True, True, True, True, True, False]

As I understand it, in my else statement, the algorithm is supposed to go up 1 row and then look at the difference of x and y and check if that slot is possible. 据我所知,在我的else语句中,该算法应该向上行1行,然后查看x和y的差异,并检查该槽是否可行。 So for instance in the most obvious case, the last element in the last row. 因此,例如在最明显的情况下,最后一行中的最后一个元素。 That would be 10(y)-11(x) which should go all the way back to index 1 on the row above it, which as we know it's True. 那将是10(y)-11(x),它应该一直回到它上面的行的索引1,我们知道它是真的。 Not entirely sure what I'm doing wrong, any help in understanding this would be greatly appreciated. 不完全确定我做错了什么,理解这一点的任何帮助将不胜感激。

Given you only feed positive values , I don't quite follow why you need a two dimensional list. 鉴于您只提供正值 ,我不太明白为什么您需要二维列表。 You can simply use a 1d list: 您只需使用1d列表:

coins = [2,3,7,8,10]
sum = 11

Next we initialize the list possible that states whether it is possible to obtain a certain value. 接下来,我们初始化possible的列表,说明是否可以获得某个值。 We set possible[0] to True since this sum can be accomplished with no coins. 我们将possible[0]设置为True因为这个总和可以在没有硬币的情况下完成。

possible = [False for _ in range(sum+1)]
possible[0] = True

Now you iterate over each coin, and over the list and "upgrade" the value if possible: 现在,您遍历每个硬币,然后遍历列表并尽可能“升级”该值:

for coin in coins:
    for i in range(sum-coin,-1,-1):
        if possible[i]:
            possible[i+coin] = True

After that, the list possible shows for each value from 0 up to (and including sum ) whether you can construct it. 之后,列表possible显示每个值从0到(并包括sum )是否可以构造它。 So if possible[sum] is True , the sum can be constructed. 因此,如果possible[sum]True ,则可以构造sum

For the given coins and sum , one gets: 对于给定的coinssum ,人们得到:

>>> possible
[True, False, True, True, False, True, False, True, True, True, True, True]

So values 0 , 2 , 3 , 5 , 7 , 8 , 9 , 10 , 11 are constructible with the coins. 所以值02357891011是constructible与硬币。

Edit: track the coins 编辑:跟踪硬币

You can also keep track of the coins by slightly modifying the code: 您还可以通过稍微修改代码来跟踪硬币:

possible = [None for _ in range(sum+1)]
possible[0] = []
for coin in coins:
    for i in range(sum-coin,-1,-1):
        if possible[i] is not None:
            possible[i+coin] = possible[i]+[coin]

Now possible looks like: 现在可能看起来像:

>>> possible
[[], None, [2], [3], None, [2, 3], None, [7], [8], [2, 7], [10], [3, 8]]

So 0 can be constructed with coins [] (no coins); 所以0可以用硬币构造[] (没有硬币); 2 can be constructed with [2] (one coin with value 2 ), 3 with [3] , 5 with [2,3] , etc. 2可以用[2] (一个值为2硬币), 3 [3]5 [2,3]等构造。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM