原题
题目大意
给出硬币面额及每种硬币的个数,求从1到m能凑出面额的个数。
题目分析
多重背包模板题,不过需要状压一波.首先定义dp[i][j]为前i个物品凑到j价格第i种硬币最多剩下多少.dp初始化为-1,点dp[0][0]=0,然后更新如下,if(dp[i-1][j]!=-1) dp[i][j]=c[i]
dp[i][j]=max(dp[i][j],dp[i][j-a[i]]).仔细观察dp更新方向可知,可以状压,把第一维去掉,然后把j的更新方向改为从小到大即可.
代码
1 #include <cstdio> 2 #include <cmath> 3 #include <iostream> 4 #include <cstring> 5 #include <algorithm> 6 #include <vector> 7 #include <string> 8 #include <utility> 9 #include <queue> 10 #include <stack> 11 const int INF=0x3f3f3f3f; 12 using namespace std; 13 14 15 int dp[100001]; 16 int v[101]; 17 int c[101]; 18 19 int main() 20 { 21 int n,m; 22 while(cin>>n>>m&&(m||n)) 23 { 24 for(int i=1;i<=n;i++) cin>>v[i]; 25 for(int i=1;i<=n;i++) cin>>c[i]; 26 memset(dp,-1,sizeof(dp)); 27 dp[0]=0; 28 for(int i=1;i<=n;i++) 29 for(int j=0;j<=m;j++) 30 { 31 if(dp[j]>=0) dp[j]=c[i]; 32 else if(j>=v[i]&&dp[j-v[i]]>0) dp[j]=dp[j-v[i]]-1; 33 } 34 int ans=0; 35 for(int i=1;i<=m;i++) if(dp[i]>=0) ans++; 36 cout<<ans<<endl; 37 memset(v,0,sizeof(v)); 38 memset(c,0,sizeof(c)); 39 } 40 return 0; 41 }