子集和的变化

时间:2014-05-23 03:35:46

标签: algorithm dynamic-programming subset subset-sum

给定一组数字,我想找出一组数字,其总和是给定数字的倍数。

我知道这是子集和的变化。但问题是数量有无数倍。所以我无法想到问题的动态问题解决方案。

那么如何将子集求和问题扩展到它呢?

3 个答案:

答案 0 :(得分:1)

对子集和的伪多项式DP解决方案使用DP状态:

DP(n, s) = Number of ways of getting a sum of s using first n elements of the set

需要O(ns)时间。如果我想找到d的所有倍数,我只对d的子集和的剩余部分感兴趣。记住模数是分配的。因此,我将DP状态更改为

DP(n, m) = Number of subsets whose sum = m mod d using the first n elements

空间减少到O(nd),时间也减少到O(nd) 在实际伪多项式解决方案中遵循的一个约定是从末端遍历DP阵列,允许您仅使用O(s)空间。这不能在这里完成。您可以做的最好是使用O(2m)内存来存储以前和当前的DP阵列。

答案 1 :(得分:0)

虽然每个(非零)数字的倍数无限多,但只有有限数量的倍数才会小于集合中所有元素的总和。换句话说,您总是可以上限由集合元素之和生成的最大倍数。这应该使您能够使用标准的伪多项式时间DP技术来解决问题。

希望这有帮助!

答案 2 :(得分:0)

以下是查找计算总和值的方法的代码。

public static void main(String [] args){

    Scanner scan=new Scanner(System.in);
    int n=scan.nextInt();//number of elements in the set
    int m=scan.nextInt();//sum needs to be calculated
    scan.nextLine();

    int[] setValue=new int[m];
    long[][] setSplit=new long[m+1][n+1];
    for(int i=0;i<m; i++)
        {
        setValue[i]=scan.nextInt();
    }
    setSplit[0][0]=1;
    //when sum is 0
    for(int i=1; i<m+1; i++)
        {
        setSplit[i][0]=1;
    }
    //when sum is more than 0 but set element is 0
    for(int j=1; j<n+1; j++)
            {
            setSplit[0][j]=0;
        }
    int temp=0;
    for(int i=1; i<=m; i++)
        {

        for(int j=1; j<n+1; j++)
            {
            setSplit[i][j]=setSplit[i-1][j];
            if(j>=setValue[i-1])
                {     

                setSplit[i][j]=setSplit[i][j]+setSplit[i][j-setValue[i-1]];

            }
        }

    }
   // System.out.println(Arrays.deepToString(setSplit));

    System.out.println(setSplit[m][n]);/*this will give number of ways sum can be calculated*/ 
}