【问题标题】:Minimum set cover最小设置覆盖
【发布时间】:2013-09-24 12:30:42
【问题描述】:

我想解决以下类型的最小集合覆盖问题。所有列表只包含 1 和 0。

我说列表A 覆盖列表B,如果您可以通过准确插入x 符号从A 生成B

考虑所有 2^n 个长度为 n 的 1 和 0 列表并设置 x = n/3。我会计算一组长度为2n/3 的最小列表,涵盖所有这些列表。

这是我开始采用的一种天真的方法。对于每个可能的长度为2n/3 的列表,我创建了一组我可以使用此函数(由 DSM 编写)从中创建的所有列表。

from itertools import product, combinations

def all_fill(source, num):
    output_len = len(source) + num
    for where in combinations(range(output_len), len(source)):
        # start with every possibility
        poss = [[0,1]] * output_len
        # impose the source list
        for w, s in zip(where, source):
            poss[w] = [s]
        # yield every remaining possibility
        for tup in product(*poss):
            yield tup

然后我以n = 6 为例创建如下集合。

n = 6
shortn = 2*n/3
x = n/3
coversets=set()
for seq in product([0,1], repeat = shortn):
    coversets.add(frozenset(all_fill(seq,x)))

我想从联合为 allset = set(product([0,1], repeat=n)) 的覆盖集中找到一个最小集。

在这种情况下,set(all_fill([1,1,1,1],2)), set(all_fill([0,0,0,0],2)), set(all_fill([1,1,0,0],2)), set(all_fill([0,0,1,1],2)) 可以。

我的目标是为n = 12 解决问题。如果有帮助的话,我很乐意使用外部库,我预计在最坏的情况下,n 的时间会成倍增长。

【问题讨论】:

  • 我实际上不确定你在问什么。你能用图形解释一下吗?
  • @Veedrac 来个小例子。设置 n = 3 和 x = 1,因此有 8 个可能的 1 和 0 列表。我想找到涵盖所有 8 个长度为 2 的最小列表集。所以取 [0,0], [1,1]。我们可以通过在这两个列表中的任何一个中添加一个 1 或 0 来制作任何长度为 3 的列表。那是不是更清楚了?我的方法是将其转换为最小集覆盖问题。
  • 我建议尝试(或至少从)成对的字符串 x 和 y,使得 y = reversebits(x) = not(x)。我认为问题的对称性意味着如果某个字符串 x 是最小覆盖集的一部分,但它本身并没有覆盖每个字符串,那么可以通过添加 reversebits(x ) 和 not(x) (以及可能的其他字符串)。如果为真,那么选择以这种方式约束的字符串对意味着您需要的字符串数量将是其他情况的一半。
  • 这里有一个简单的上限:如果你有一组 k 个字符串 S[i], 1 { 0.S[i].0, 1.S[i].1, 0.S[i].1, 1.S[i].0 },其中 . 表示串联。显然这是松散的,因为从您的示例中我们有 f(3) = 2 但 f(6) = 4
  • @j_random_hacker 谢谢。我真的想要一个精确的算法。我有很好的上限和下限,但我也想计算小案例的最佳解决方案。

标签: python algorithm set-cover


【解决方案1】:

我写了一个小程序来写一个整数程序来解决 CPLEX 或其他 MIP 求解器。下面是 n=12 的解。


from collections import defaultdict
from itertools import product, combinations

def all_fill(source, num):
    output_len = (len(source) + num)
    for where in combinations(range(output_len), len(source)):
        poss = ([[0, 1]] * output_len)
        for (w, s) in zip(where, source):
            poss[w] = [s]
        for tup in product(*poss):
            (yield tup)

def variable_name(seq):
    return ('x' + ''.join((str(s) for s in seq)))
n = 12
shortn = ((2 * n) // 3)
x = (n // 3)
all_seqs = list(product([0, 1], repeat=shortn))
hit_sets = defaultdict(set)
for seq in all_seqs:
    for fill in all_fill(seq, x):
        hit_sets[fill].add(seq)
print('Minimize')
print(' + '.join((variable_name(seq) for seq in all_seqs)))
print('Subject To')
for (fill, seqs) in hit_sets.items():
    print(' + '.join((variable_name(seq) for seq in seqs)), '>=', 1)
print('Binary')
for seq in all_seqs:
    print(variable_name(seq))
print('End')

MIP - Integer optimal solution:  Objective =  1.0000000000e+01
Solution time =    7.66 sec.  Iterations = 47411  Nodes = 337

CPLEX> Incumbent solution
Variable Name           Solution Value
x00000000                     1.000000
x00000111                     1.000000
x00011110                     1.000000
x00111011                     1.000000
x10110001                     1.000000
x11000100                     1.000000
x11001110                     1.000000
x11100001                     1.000000
x11111000                     1.000000
x11111111                     1.000000
All other variables matching '*' are 0.
CPLEX> 

【讨论】:

  • 谢谢。这是完美的。
猜你喜欢
  • 2016-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多