count包含set的所有元素的子集的集合

时间:2017-09-22 15:40:44

标签: set subset combinations

给定包含M 1的集合S(M),计算所有非空子集的集合,使得每个集合的并集生成S(M)。子集的基数也可以是K,其中1 <1。 K <= M和M可以取值达到10 ^ 5.

S(M) = {1,1,1,1}, K = 2.

possible collections can be 
{{1,1},{1,1}},
{1},{1},{1,1}},
{{1,1},{1},{1}}

我已经看过几个答案,但我相信它们与我的不同。

我还阅读Stirling number of second kind但我仍然希望在该公式中纳入子集基数的条件。

我编写了一个可能的递归解决方案,该解决方案不适用于M的大值

如果有人需要更多信息,请告诉我。

任何帮助或指导都将不胜感激。

此致

的Ajay

2 个答案:

答案 0 :(得分:0)

如果我正确地理解了这个问题中的术语,你会问有多少种方法将长度为 M 的序列ABCDEFGHIJ分成单词(例如,ABC DE FGH IJ ......)每个长度不大于 K 。 (对于给出的例子,答案是五:ABCD,AB CD,A BC D,AB CD和AB CD。)这是stars and bars解决的问题的双重问题,因为限制是在子集的大小而不是它们的数量。

我没有尝试使用封闭式解决方案,但直接dynamic programming攻击适用于O( M ^ 2 K ) time:让 C _n为第一个 n 字母的可能性。所有 n &lt; 0 C _0 = 1, C _n为0。对于 n &gt; 0,我们有 C _n = sum( i = [1 .. K ]) C _(名词 - I 的)。只需按顺序计算值,直到达到 C _M。 (当然,将最后的 K 值保留在用作SIPO shift register的队列中就足够了。)

请注意,值变得非常快: M = 100且 K = 2,我得到5.7e20的可能性;将 K 更改为10会产生6.1e29。提到的10 ^ 5的 M (再次 K = 2)得到4.2e20898。因此,我将 M 的额外因子包括在与任意精度算术相对应的复杂度中。

答案 1 :(得分:0)

方法应该是

Given M and K

Find the max number of divisions(subsets)
Find the min number of divisions(subsets)

Iterate from max to min using i
-Apply DP to find different combinations of sizes of subsets. 
-A permutation of each combination should yield a count for that number of combinations(i). 
-Sum up all the counts.

以下是带有DP的此逻辑的Java实现。变量steptoGo分别对应MK。我尝试用一​​些随机数运行它但是很低。

  

注意:您还需要更新静态数组维度   当使用巨大的M值时。

import java.util.Arrays;
public class HelloWorld{


    public static int step = 4;
    public static long[][] dMem = new long[100][100];

     public static void main(String []args){

        int toGo = 30;
        int max = toGo;
        int min = toGo/step;
        long temp = 0;

        long count = 0;
        for(int i = max; i >= min; i--){
            temp = nSteps(i, toGo);
            temp = temp == -1 ? 0 : temp;
            count += temp;
           // System.out.println(count+"\n");
        }
        System.out.println("Num of ways = "+count);
     }

     public static long nSteps( int n, int toGo ){

         long steps = 0, temp = 0;
         //System.out.println(" n = "+n+" toGo = "+toGo);
         if( n == toGo ) return 1;
         if( n > toGo || n <= 0 || toGo <= 0) return -1;
         if( dMem[n][toGo] != 0 ) return dMem[n][toGo];
         for( int i = 1; i <= step; i++){
             temp = nSteps( n-1, toGo-i );
             temp = temp == -1 ? 0 : temp;
             steps += temp;
         }
         steps = steps == 0 ? -1 : steps;
         dMem[n][toGo] = steps;
         return steps;
     }
}