【问题标题】:Variation of subset sum子集和的变化
【发布时间】:2014-05-23 03:35:45
【问题描述】:

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

我知道这是子集和的变体。但问题是一个数字有无限的倍数。所以我想不出一个动态问题的解决方案。

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

【问题讨论】:

  • 有用link
  • 为什么?应该足以让您开始吗? dp state 可以是[index][modulus with given number]。
  • @PhamTrung 我的意思是链接首先进入无效页面。现在链接已修复,谢谢。
  • @PhamTrung 但是奇怪的人使用 Quora 而不是 SO
  • 知识来自各个方面 :) IMO 尽管 SO 在编程方面享有更高的声誉,但 Quora 正在快速增长。

标签: algorithm dynamic-programming subset subset-sum


【解决方案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 数组。

【讨论】:

    【解决方案2】:

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

    希望这会有所帮助!

    【讨论】:

      【解决方案3】:

      这是查找计算总和值的方法数量的代码。

      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*/ 
      }
      

      【讨论】:

        猜你喜欢
        • 2015-12-24
        • 1970-01-01
        • 1970-01-01
        • 2011-05-03
        • 2018-01-29
        • 1970-01-01
        • 2020-05-18
        • 1970-01-01
        • 2017-03-28
        相关资源
        最近更新 更多