题意:硬币分别有 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; }