poj 1742 多重背包问题 dp算法

题意:硬币分别有 A1.....An种,每种各有C1......Cn个,问组成小于m的有多少种

思路:多重背包问题

     dp[i][j]表示用前i种硬币组成j最多剩下多少个  dp=-1的表示凑不齐

      dp[0][0]=0;

for(int i=0;i<n;i++)

    for(int j=0;j<=m;j++)

{    if(dp[i][j]>=0)   dp[i+1][j]=c[i];  //表示用前i种可以凑齐j元,自然就全部剩下了

      else if(j<a[i]||dp[i+1][j-a[i]]<=0) dp[i+1][j]=-1;  //表示没法凑

      else dp[i+1][j]=dp[i+1][j-a[i]]-1;   //表示用了i这种硬币

}

如何数组重用呢?

 dp[j]表示前i种硬币(循环)凑成j元最多剩下

dp[0]=0;

for(int i=0;i<n;i++)

for(int j=0;j<=m);j++)

{if(dp[j]>=0) dp[j]=c[i];

else if(j<a[i]||dp[j-a[i]]<=0) dp[j]=-1;

else dp[j]=dp[j-a[i]]-1;}

解决问题的代码:

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
int a[116];
int c[116];
int dp[100000 + 16];
int main()
{
        int n,m;
        while (scanf("%d%d", &n, &m) != EOF)
        {
               if (n == 0 && m == 0) break;
               for (int i = 0; i < n; i++)
                       scanf("%d", &a[i]);
               for (int i = 0; i < n; i++)
                       scanf("%d", &c[i]);
               memset(dp, -1, sizeof(dp));
               dp[0] = 0;
               for(int i=0;i<n;i++)
                       for (int j = 0; j <= m; j++)
                       {
                              if (dp[j] >= 0) dp[j] = c[i];
                              else if (j < a[i] || dp[j - a[i]] <= 0) dp[j] = -1;
                              else dp[j] = dp[j - a[i]] - 1;
                       }
               int ans = 0;
               for (int i = 1; i <= m; i++)
               {
                       if (dp[i] >= 0) ++ans;
               }
               printf("%d
", ans);
        }
        return 0;
}
君子知命不惧,自当日日自新
原文地址:https://www.cnblogs.com/xuxiaojin/p/9406830.html