给定一个元素宇宙U = {1,2,3,...,n}和这个宇宙中的许多集合{S1,S2,...,Sm},我们可以得到的最小集合是多少创建将覆盖每组m中至少一个元素?
例如,给定以下元素U = {1,2,3,4}并设置S = {{4,3,1},{3,1},{4}},以下几组将涵盖每组至少一个元素: {1,4} 要么 {3,4} 所以这里要求的最小尺寸是2。
有关如何扩大规模以解决m = 100或m = 1000套问题的任何想法?或者想一想如何用R或C ++编写代码?
上面的示例数据,使用R library(sets)
。
s1 <- set(4, 3, 1)
s2 <- set(3, 1)
s3 <- set(4)
s <- set(s1, s2, s3)
干杯
答案 0 :(得分:7)
这是hitting set problem,它基本上设置为覆盖元素和集合的角色互换。假设A = {4,3,1}且B = {3,1}且C = {4},则元素集包含关系为
A B C
1 + + -
2 - - -
3 + + -
4 + - +
所以你基本上想要用集合1 = {A,B}和2 = {}和3 = {A,B}和4 = {A,C}来解决覆盖{A,B,C}的问题
在实践中解决集合覆盖的重要实例的最简单方法可能是找到一个带有R或C ++接口的整数编程包。您的示例将以LP格式呈现为以下整数程序。
Minimize
obj: x1 + x2 + x3 + x4
Subject To
A: x1 + x3 + x4 >= 1
B: x1 + x3 >= 1
C: x4 >= 1
Binary
x1 x2 x3 x4
End
答案 1 :(得分:2)
起初我误解了问题的复杂性,并提出了一个找到覆盖m组的集合的函数 - 但我意识到它不一定是最小的集合:
cover <- function(sets, elements = NULL) {
if (is.null(elements)) {
# Build the union of all sets
su <- integer()
for(si in sets) su <- union(su, si)
} else {
su <- elements
}
s <- su
for(i in seq_along(s)) {
# create set candidate with one element removed
sc <- s[-i]
ok <- TRUE
for(si in sets) {
if (!any(match(si, sc, nomatch=0L))) {
ok <- FALSE
break
}
}
if (ok) {
s <- sc
}
}
# The resulting set
s
}
sets <- list(s1=c(1,3,4), s2=c(1,3), s3=c(4))
> cover(sets) # [1] 3 4
然后我们可以计时:
n <- 100 # number of elements
m <- 1000 # number of sets
sets <- lapply(seq_len(m), function(i) sample.int(n, runif(1, 1, n)))
system.time( s <- cover(sets) ) # 0.53 seconds
不是太糟糕,但仍然不是最小的一个。
显而易见的解决方案:生成元素的所有排列并传递给封面函数并保持最小的结果。这将接近“永远”。
另一种方法是生成有限数量的随机排列 - 这样就可以得到最小集合的近似值。
ns <- 10 # number of samples
elements <- seq_len(n)
smin <- sets
for(i in seq_len(ns)) {
s <- cover(sets, sample(elements))
if (length(s) < length(smin)) {
smin <- s
}
}
length(smin) # approximate smallest length
答案 2 :(得分:1)
如果将每个集限制为包含2个元素,则可以使用np-complete问题节点封面。我猜想更普遍的问题也是NP完全(对于确切的版本)。
答案 3 :(得分:1)
如果您只对算法(而不是有效/可行算法)感兴趣,则可以简单地生成基数增加的宇宙子集,并检查与S中所有集合的交集是否为非空。一旦你得到一个有效的就停止;基数是可能的最小值。
这是2 ^ | U |的复杂性在最糟糕的情况下,我认为。鉴于Foo Bah的回答,我认为你不会得到多项式时间答案......