最常见的大小为k的子集

时间:2012-02-17 12:39:45

标签: algorithm combinatorics

假设您有一个整数范围S1,...,Sn的子集R={1,2,...,N}和一个整数k的列表。是否有一种有效的方法来查找C大小为R的子集k,以便CSi的最大数量的子集?< / p>

例如,请R={1,2,3,4}k=2

S1={1,2,3}
S2={1,2,3}
S3={1,2,4}
S4={1,3,4}

然后我想要返回C={1,2}C={1,3}(并不重要)。

3 个答案:

答案 0 :(得分:2)

我认为你的问题是NP-Hard。考虑二分图,左边的节点是你的集合,右边的节点是整数{1, ..., N},如果集合包含整数,则在两个节点之间有一条边。然后,找到大小为k的公共子集,它是Si的最大数量的子集,相当于找到具有最大边数{{}的完整二分子图K(i, k) 1}}。如果您可以在多项式时间内执行此操作,则可以通过尝试每个固定的i*k找到在多项式时间内具有最大边数K(i, j)的完整二分子图i*j。但NP-Complete中的这个问题(Complete bipartite graph)。

因此,除非P = NP,否则您的问题没有多项式时间算法。

答案 1 :(得分:1)

假设我理解你的问题,我相信对于相当小的集合来说这是直截了当的。

我将使用 Mathematica 代码进行说明,但这个概念是通用的。

我从{1 .. 8}集中生成长度为10的{​​{1}}个随机子集:

4
ss = Subsets[Range@8, {4}] ~RandomSample~ 10

我将这些转换为每个子集中每个数字存在的二进制数组:

{{1, 3, 4, 6}, {2, 6, 7, 8}, {3, 5, 6, 7}, {2, 4, 6, 7}, {1, 4, 5, 8},
 {2, 4, 6, 8}, {1, 2, 3, 8}, {1, 6, 7, 8}, {1, 2, 4, 7}, {1, 2, 5, 7}}

Mathematica graphics

这是10个子集的十列,以及元素{1 .. 8}的8行。

现在生成所有可能的目标子集(大小a = Normal@SparseArray[Join @@ MapIndexed[Tuples[{##}] &, ss] -> 1]; Grid[a] ):

3

获取“密钥”并从数组中提取这些行并执行BitAnd操作(如果所有列等于keys = Subsets[Union @@ ss, {3}]; ,则返回1),然后计算1的数量。例如,对于密钥1,我们有:

{1, 6, 8}

Mathematica graphics

BitAnd之后:

Mathematica graphics

为每个键执行此操作:

a[[{1, 6, 8}]]

然后找到该列表的最大元素的位置,并提取counts = Tr[BitAnd @@ a[[#]]] & /@ keys; 的相应部分:

keys
keys ~Extract~ Position[counts, Max@counts]

如果有足够的内存,此过程可以快速处理更大的内存。从50,000个随机选择的长度{{1, 2, 7}, {2, 4, 6}, {2, 4, 7}, {2, 6, 7}, {2, 6, 8}, {6, 7, 8}} 的子集开始,来自{1 .. 30}:

7

长度ss = Subsets[Range@30, {7}] ~RandomSample~ 50000; 的最大子集在大约9秒内计算:

4
AbsoluteTiming[
  a = Normal@SparseArray[Join @@ MapIndexed[Tuples[{##}] &, ss] -> 1];
  keys = Subsets[Union @@ ss, {4}];
  counts = Tr[BitAnd @@ a[[#]]] & /@ keys;
  keys~Extract~Position[counts, Max@counts]
]

我应该补充一点, Mathematica 是一种高级语言,这些操作都在通用对象上,因此如果真的在二进制级别完成,这应该更快,内存效率更高。 / p>

答案 2 :(得分:1)

我希望我不会误解这个问题......这是SWI-Prolog的解决方案

:- module(subsets, [solve/0]).
:- [library(pairs),
    library(aggregate)].

solve :-
    problem(R, K, Subsets),
    once(subset_of_maximal_number(R, K, Subsets, Subset)),
    writeln(Subset).

problem(4, 2,
[[1,2,3], [1,2,3], [1,2,4], [1,3,4]]).

problem(8, 3,
[[1, 3, 4, 6], [2, 6, 7, 8], [3, 5, 6, 7], [2, 4, 6, 7], [1, 4, 5, 8],
 [2, 4, 6, 8], [1, 2, 3, 8], [1, 6, 7, 8], [1, 2, 4, 7], [1, 2, 5, 7]]).

subset_of_maximal_number(R, K, Subsets, Subset) :-
    flatten(Subsets, Numbers),
    findall(Num-Count,
        (   between(1, R, Num),
            aggregate_all(count, member(Num, Numbers), Count)
        ), NumToCount),
    transpose_pairs(NumToCount, CountToNumSortedR),
    reverse(CountToNumSortedR, CountToNumSorted),
    length(Subset, K), % list of free vars
    prefix(SolutionsK, CountToNumSorted),
    pairs_values(SolutionsK, Subset).

测试输出:

?- solve.
[1,3]
true ;
[7,6,2]
true.

编辑我认为上述解决方案是错误的,因为返回的内容不能是任何输入的子集:这里(注释)解决方案没有这个问题:

:- module(subsets, [solve/0]).
:- [library(pairs),
    library(aggregate),
    library(ordsets)].

solve :-
    problem(R, K, Subsets),
    once(subset_of_maximal_number(R, K, Subsets, Subset)),
    writeln(Subset).

problem(4, 2,
[[1,2,3], [1,2,3], [1,2,4], [1,3,4]]).

problem(8, 3,
[[1, 3, 4, 6], [2, 6, 7, 8], [3, 5, 6, 7], [2, 4, 6, 7], [1, 4, 5, 8],
 [2, 4, 6, 8], [1, 2, 3, 8], [1, 6, 7, 8], [1, 2, 4, 7], [1, 2, 5, 7]]).

subset_of_maximal_number(R, K, Subsets, Subset) :-
    flatten(Subsets, Numbers),
    findall(Num-Count,
        (   between(1, R, Num),
            aggregate_all(count, member(Num, Numbers), Count)
        ), NumToCount),

    % actually sort by ascending # of occurrences
    transpose_pairs(NumToCount, CountToNumSorted),
    pairs_values(CountToNumSorted, PreferredRev),

    % we need higher values first
    reverse(PreferredRev, Preferred),

    % empty slots to fill, preferred first
    length(SubsetP, K),
    select_k(Preferred, SubsetP),

    % verify our selection it's an actual subset of any of subsets
    sort(SubsetP, Subset),
    once((member(S, Subsets), ord_subtract(Subset, S, []))).

select_k(_Subset, []).
select_k(Subset, [E|R]) :-
    select(E, Subset, WithoutE),
    select_k(WithoutE, R).

试验:

?- solve.
[1,3]
true ;
[2,6,7]
true.