我该如何编辑这个算法,以便它在不替换或重用元素的情况下创建组合?

How do I edit this algorithm so that it creates combinations without replacement or reusing an element?

我对计算机科学还很陌生 - 这是我的第一个程序。我写了一个 python 程序,它从 excel sheet "Labels":"Values" 的两列中获取数据,并将它们重新配置到标签列表中,标签列表各自的值总和为30. 每个标签都是唯一的,只出现一次,但不同的标签可以有相同的值。

但是,当我第一次应用我的程序时,运行时间将近 30 分钟,因为算法正在创建标签的所有可能组合。显然给定 50 个值小于 10 的标签,这是很多可能的组合。

我需要一些帮助来编辑我当前的算法,以便它创建独特的组。使用标签后,我不希望它出现在任何其他组中。

目前我的代码如下所示:

def combinator(X): #this function pulls two lists together to create a dictionary
  from xlrd import open_workbook
  wb = open_workbook(X)
  L = []
  P = []
  for s in wb.sheets(): 
      for col in range(s.ncols):
          for row in range(s.nrows):
              if row !=0:
                  l = s.cell(row,0).value
                  L.append(l)

                  p = s.cell(row,1).value
                  P.append(p)
  Lots = L[0:(len(L)/2)]
  Pallets = P[0:(len(L)/2)]
  D = dict(zip(Lots,Pallets))
  return D


def grouper(D, N):#this finds combinations of 30 and puts them in groups
  from itertools import combinations
  groups_of_thirty = []

  for l in range(0, len(D)):
      for y in combinations(D.items(), l):
          keys = []
          sum = 0

          for key, value in y:
              keys.append(key)
              sum += value

          if sum == N:
              groups_of_thirty.append(keys)

  flattened = [v for flat in groups_of_thirty for v in flat]
  K = D.keys()
  s = set(K)
  remainder = list(s - set(flattened))
  list(groups_of_thirty)
  return groups_of_thirty, \
       remainder


def transposer(G):#this exports the final list into each cell and writes  the spreadsheet as a csv to a different directory.
    import os
    os.chdir(Q)
    import csv
    with open(O, "wb") as f:
        writer = csv.writer(f)
        str(writer.writerows(G))
    return

transposer(grouper(combinator(I),N))

希望得到任何帮助 - 首选逻辑或伪代码,但一些具有不常见语法的指针会有所帮助,因为我是新手。

谢谢!

编辑:这是 excel sheet.

中示例数据的屏幕截图

Screenshot of Excel sheet with Input and Desired Output

这是我在评论中提到的线性规划方法:

import pandas as pd
from pulp import *
import random
random.seed(0)
num_items = 50
labels = ['Label{0:02d}'.format(i) for i in range(num_items)]
values = [random.randint(5, 30) for _ in range(num_items)]
df = pd.DataFrame({'Value': values}, index=labels)
feasible_solutions = []
var = LpVariable.dicts('x', labels, 0, 1, LpInteger)
prob = pulp.LpProblem('Fixed Sum', pulp.LpMinimize)
prob += 0
prob += lpSum([var[label] * df.at[label, 'Value'] for label in labels]) == 30

while prob.solve() == 1:
    current_solution = [label for label in labels if value(var[label])]
    feasible_solutions.append(current_solution)
    prob += lpSum([var[label] for label in current_solution]) <= len(current_solution) - 1

labels 是包含标签的常规列表,values 是 5 到 30 之间的随机整数。它以空集开头。

此代码中最重要的元素之一是 var。它是取值 0 或 1 的决策变量。当您在解决方案中包含特定标签时,它取值 1,否则它等于零。

例如,假设您有此列表 [12, 7, 5, 13]。这里,对于可能的解决方案var00(12),var02(5)和var03(13)可以取值1。

下一行创建一个线性规划问题。我们指定了一个任意的 objective 函数 (prob += 0),因为我们没有最小化或最大化任何函数 - 我们试图找到所有可能的解决方案。

这些解决方案应满足下一行中的约束条件。在这里,var[label] 是我提到的二元决策变量。如果它包含在解决方案中,则它取值 1,然后 1 乘以它的值。所以我们只对集合中包含的项目的值求和。它们的总和应该等于 30。在这里,prob.solve() 会生成一个可行的解决方案,但由于您想要所有可行的解决方案,因此您在 while 循环中调用 prob.solve()。只要能return个可行解(==1)就继续循环。但是在每次迭代中,我们应该排除当前的解决方案,以便我们的搜索 space 减少。它由最后一行完成。例如,如果在当前解决方案中我们有 var00var04var07,对于后续问题,它们的总和应该小于 3(所有三个不应该同时为 1时间)。如果你 运行 这个,它会为你的问题生成所有可能的解决方案。

这是前五个:

feasible_solutions[:5]
Out: 
[['Label00', 'Label47'],
 ['Label17', 'Label46'],
 ['Label42', 'Label45'],
 ['Label03', 'Label13', 'Label47'],
 ['Label02', 'Label03', 'Label48']]

这些是它们的值:

Out: [[17, 13], [9, 21], [11, 19], [6, 11, 13], [18, 6, 6]]