多重部分和问题

描述:

  N种不同数字ai每种mi个,判断是否可以选择若干个使得和为K
  N<=100,k<=100000,ai,mi<=100000,均大于零。

分析:

  裸算法:

    DP[I][K]=0..1——前i个物品是否可以组成K

    for (int i=1;i<=n;i++)
    for (int k=0;k<=K;k++)
      if (Dp[i-1][k])
        for (int c=0;c<=mi;c++)
          Dp[i][k+c*ai]=1;

    时间复杂度显然是n*k*mi sum i=1..n 十分巨大

    因为如果使用DP求BOOL往往很浪费,放弃了许多可以利用的信息。

    如果我们不仅仅求出能否得到目标,并且记录下来剩下来多少个,可以减小很大的复杂度。

    改为DP[I][K]为前I组成K,第I可以剩下最多为多少。

      for (int i=1;i<=n;i++)
      for (int k=0;k<=K;k++)
        if (k>=ai)
        {
          if (Dp[i-1][k])
          {
            //上一个已经可以构成
            Dp[i][k]=mi;
          }

          if (Dp[i][k-ai])
          {
            //如果DP[I][K]可以构成,那么DP[I][K-AI]是必然可以构成的
            Dp[i][k]=Dp[i][k-ai]-1;
          }
        }
        else
        {
          Dp[i][k]=-1;
        }

原文地址:https://www.cnblogs.com/dandi/p/3949929.html