【问题标题】:All possible exact sums from multiple arrays来自多个数组的所有可能的精确总和
【发布时间】:2020-02-20 12:01:31
【问题描述】:

我遇到了以下问题,我的代码已经变得一团糟,我陷入了困境。

您可以在一些商店消费(大约 15 美元,只是一些正整数) 您只能在两种情况下使用这笔钱:

1) 您从每家商店只购买一件商品。

2) 你花光了所有的钱(没有剩余,也没有债务)

找出所有可能的方式来满足上述要求。

实际上,您获得了一个预算 int 和一些类似

的数组

9 和 [[1,2,3],[0,5],[2,3,8]]

其中每个内部数组列出了商店中商品的价格。可以有任意多的商店,有任意多的物品。成本不能是负数,但它们可以是免费的!

这里的预期解决方案是:

[[1,5,3],[2,5,2],[1,0,8]]

由于每个数组包含来自每个商店的一个项目,每个总计 9 个,并且存在所有可能性。 只是为了让它更难,速度是最重要的。

以下是我的代码已经陷入疯狂并且几乎完全缺乏功能:

def Stepper(bud,LOL):
    n=len(LOL)
    lasts=[]
    indices=[0 for j in range(n)]
    focus=0
    funds=[0 for j in range(n+1)]
    funds[0]=bud
    sols=[]
    moveable=[]
    for j in range(n):
        length=len(LOL[j])
        if(length==0):
            return []
        lasts.append(length-1)
        if(moveable==[]):
            if(length==1):
                funds[j+1]=funds[j]-LOL[j][0]
            else:
                moveable.append(j)
                focus=j
    while(moveable!=[]):
        while(LOL[focus][indices[focus]] > funds[focus]):
            indices[focus]+=1
        if(indices[focus]==lasts[focus]):
            if(moveable[-1]==focus):
                moveable.remove(focus)
            if(moveable==[]):
                if(focus<n-1):
                    moveable.append(focus+1)
        funds[focus+1]=funds[focus]-LOL[focus][indices[focus]]
        #print(n,lasts,indices,focus,moveable,funds,sols)
        if((funds[focus+1]!=0) and (focus<n-1)):
                focus+=1
                indices[focus]=0
        else:
            if(funds[focus+1]==0):
                for j in range(focus+1,n):
                    indices[j]=lasts[j]
                sols.append(list(indices))
            if(moveable[-1]==n-1):
                moveable.remove(n-1)
            if(moveable!=[]):
                focus=moveable[-1]
                indices[focus]+=1
                if(indices[focus]==lasts[focus]):
                    if(moveable[-1]==focus):
                        moveable.remove(focus)
                    if(moveable==[]):
                        if(focus<n-1):
                            moveable.append(focus+1)
                funds[focus+1]=funds[focus]-LOL[focus][indices[focus]]
                focus+=1
                indices[focus]=0
    return(sols)

bud 是预算,LOL 是列表列表(商店和价格)

【问题讨论】:

  • 你好,你需要实现树遍历深度优先算法,从右上角(第一家商店最后价格)到左下角(最后商店第一价格)。通用原则到处都有很好的描述。通过检查当前balance(所有遍历节点的总和)budget,还可以显着提高性能,因此当它克服时,您只需跳过以下无法通过 itertools.product 获得的深入遍历。跨度>

标签: python arrays optimization


【解决方案1】:

这是一个组合问题。商店 1 中的哪些商品与商店 2 中的哪些商品以及商店 3...n 中的哪些单品相加得到某个数字?

Python 的标准库有一个函数可以为您生成所有这些组合,从而为您节省了嵌套的 for 循环。很方便的itertools.product

>>> import itertools
>>> budget = 9
>>> shops = [[1, 2, 3], [0, 5], [2, 3, 8]]
>>> list(itertools.product(*shops))
[(1, 0, 2),
 (1, 0, 3),
 (1, 0, 8),
 (1, 5, 2),
 (1, 5, 3),
 (1, 5, 8),
 (2, 0, 2),
 (2, 0, 3),
 (2, 0, 8),
 (2, 5, 2),
 (2, 5, 3),
 (2, 5, 8),
 (3, 0, 2),
 (3, 0, 3),
 (3, 0, 8),
 (3, 5, 2),
 (3, 5, 3),
 (3, 5, 8)]

接下来我们要去掉所有不满足我们条件的组合(即价格正好加起来等于总预算)。让我们使用内置的filter 函数来获得我们的解决方案:

>>> list(filter(lambda prices: sum(prices) == budget, itertools.product(*shops))
[(1, 0, 8), (1, 5, 3), (2, 5, 2)]

【讨论】:

    【解决方案2】:

    如果你被允许使用 itertools

    import itertools
    x =  [[1,2,3],[0,5],[2,3,8]]
    combinations = list(itertools.product(*x))
    for o in combinations:
        if sum(o) == 9:
            print(o)
    

    输出:

    (1, 0, 8)
    (1, 5, 3)
    (2, 5, 2)
    

    取决于this 问题。

    【讨论】:

      【解决方案3】:

      如果您仍然对算法感兴趣,这是我的解决方案:

      def Stepper(bud, shops, combinations = None):
          if combinations is None:
              combinations = [[item] for item in shops[0]] 
              #if empty, populate  the list of combinations with list containing every item of the first shop
              shops = shops[1:] #remove the shop from the list
      
          if len(shops) == 1: #if only one shop remains
              counter = 0
              while counter < len(combinations):
                  comb = combinations[counter] # take a combination
                  diff = bud - sum(comb)       # check how much you have to spend
                  if diff in shops[0]: 
                      #if the shop have what you're looking for you keep the combination
                      comb.append(diff)
                      counter += 1
                  else:
                      # there is no way to spend all the money
                      combinations.remove(comb)
      
              return combinations
      
          new_combinations = list()
          for old_combination in combinations:
              for item in shops[0]:
                  comb = old_combination + [item] #create every possible combination mixing the old combinations with the items of the next stop
                  if sum(comb) < bud: new_combinations.append(comb) # the combination is valid only if you have 0 or more money left
          return Stepper(bud,shops[1:],new_combinations) # calculate combinations with the remaining shops
      

      要测试它只需调用

      Stepper(9, [[1,2,3],[0,5],[2,3,8]])
      

      【讨论】:

        【解决方案4】:

        这是一种简单但可能效率低下的解决方法。

        In [70]: s = [[1,2,3],[0,5],[2,3,8]]    
        In [71]: n = 9
        In [72]: for x in s[0]:
            ...:     for y in s[1]:
            ...:         for z in s[2]:
            ...:             if x+y+z == n:
            ...:                 print(x,y,z)
            ...:
        1 0 8
        1 5 3
        2 5 2
        

        从第一个商店开始,对于任何选项,迭代下一个商店,然后再次,对于第二个商店的任何选项,迭代下一个商店的选项。将所有价格相加并检查总和是否等于 9。

        【讨论】:

        • 店铺数量不定。即使忽略效率问题,这个答案也只支持固定数量的商店。
        猜你喜欢
        • 1970-01-01
        • 2019-07-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多