题目链接:http://poj.org/problem?id=1742
与一般的背包问题不一样,这是要计算满足条件的情况的数量,而不是计算最值,一开始的思路就是按照书上的类比:
dp[i][j] := 用前i种硬币能否凑成j
递推:dp[i][j] = (dp[i – 1][j – k * A[i]])为真的时候
但是 MLE,其实一点都不惊讶吧,数组开那么大肯定会出问题呀,所以只能放弃二维数组:
dp[j] := 在第i次循环时之前表示用前 i-1 种硬币凑成 j 时第 i 种硬币最多能剩余多少个(-1表示配不出来),循环之后就表示第i次的状态
ac代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #define MAX_N 101 6 using namespace std; 7 int n,m; 8 int a[MAX_N],c[MAX_N]; 9 int dp[100005]; 10 11 void solve(){ 12 memset(dp,-1,sizeof(dp)); 13 dp[0]=0; 14 for(int i=0;i<n;i++){ 15 for(int j=0;j<=m;j++){ 16 if(dp[j]>=0) 17 dp[j]=c[i]; 18 else if(j<a[i]||dp[j-a[i]]<=0) 19 dp[j]=-1; 20 else 21 dp[j]=dp[j-a[i]]-1; 22 } 23 } 24 int ans=0; 25 for(int i=1;i<=m;i++) 26 if(dp[i]>=0) ans++; 27 printf("%d ",ans); 28 } 29 30 int main(void){ 31 while(scanf("%d%d",&n,&m)&&(n||m)){ 32 for(int i=0;i<n;i++) scanf("%d",&a[i]); 33 for(int j=0;j<n;j++) scanf("%d",&c[j]); 34 solve(); 35 } 36 37 return 0; 38 }