最初、私は問題の複雑さを誤解し、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
それほど悪くはありませんが、それでも最小のものではありません。
明らかな解決策: 要素のすべての順列を生成し、それをカバー関数に渡し、最小の結果を保持します。これは「永遠」に近いでしょう。
もう 1 つのアプローチは、限られた数のランダム順列を生成することです。このようにして、最小セットの近似値を取得します。
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