假设我有很多用户,每个用户都有一组介于0
和n
之间的数字。例如,一个用户可能有一个集合{3, 7}
,另一个用户可能有{7, 8, 9}
,等等。
我想得到最小的用户数,如果我取他们所有集合的并集,我将得到0
和n
之间所有数字的集合。
如果你能想出一种方法,让我给每个用户分配一个可变价格(而不是像上面那样使用1
),这样算法就能找到具有最低总价的用户组合。
我在Python(like this one)中见过处理约束满足的包,但我不知道如何使用它们如果它们能被用来做这个,太好了。
最佳答案
这里有一个PuLP/GLPK的解决方案。我以前从来没有用过纸浆,但它是在皮皮上,似乎做的工作GLPK相当不错而且免费。
from collections import defaultdict, namedtuple
from pulp import *
User = namedtuple('User', ('coverage', 'price'))
def solvesetcover(users):
vars = [LpVariable('x{}'.format(i), 0, 1, cat='Binary') for i, user in enumerate(users)]
prob = LpProblem()
totals = defaultdict(int)
for user, var in zip(users, vars):
prob += user.price * var
for elt in user.coverage:
totals[elt] += var
for total in totals.values():
prob += total >= 1
GLPK(msg=0).solve(prob)
return [user for user, var in zip(users, vars) if value(var)]
if __name__ == '__main__':
users = []
users.append(User({1, 2, 3, 4, 5, 6, 7}, 1.16))
users.append(User({8, 9, 10, 11, 12, 13, 14}, 1.08))
users.append(User({1, 8}, 1.04))
users.append(User({2, 3, 9, 10}, 1.02))
users.append(User({4, 5, 6, 7, 11, 12, 13, 14}, 1.01))
print(solvesetcover(users))