题目大意:给你n个种类的钱和对应的数量,同统计一下从1到m能够凑成的钱有多少个;
解题思路:多重背包的题,少了一个类似于重量上限的限制,这里其实就是那个m,每次不断变化的1到m的值就是限制,最后统计下多少dp数组更新过就是能够凑到的,这里不用从1到m枚举上限,直接上限填m,这样在更新完n个种类后m之前由于要到达m必然解决比他小的包,简言之,就是前面的dp已经优化了(你想我们既然都优化到m了,像m-1,m-2,m-3...2,1这些是不是都优化了),以下模板。(ps:HDOJ这题我交了一个有BUG的代码上去居然AC了,虽然是998ms
AC代码如下:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<queue>
#include<map>
#include<math.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e5+10;
int dp[maxn],value[110],num[110];
int max(int a,int b)
{
return a>b?a:b;
}
//每次最大值会更新
void pack01(int v,int h,int m)
{
for(int i=m;i>=v;i--)
dp[i]=max(dp[i],dp[i-v]+h);
return ;
}
void packall(int v,int h,int m)
{
for(int i=v;i<=m;i++)
dp[i]=max(dp[i],dp[i-v]+h);
return ;
}
void packs(int v,int h,int m,int cnt)
{
if(cnt*v>=m)
{
packall(v,h,m);
return ;
}
int k=1;
while(k<=cnt)
{
pack01(k*v,k*h,m); //更新物品的比例
cnt-=k; //二进制思路压缩背包物品的数量
k<<=1;
}
if(cnt)
pack01(cnt*v,cnt*h,m); //最后一件
return ;
}
/*
dp[i]:不超过i的合成的最大的钱
*/
int main()
{
int n,m,cnt,i,j;
while(cin>>n>>m && n+m)
{
dp[0]=cnt=0;
for(i=1;i<=m;i++)
dp[i]=-inf;
for(i=0;i<n;i++)
cin>>value[i];
for(i=0;i<n;i++)
cin>>num[i];
for(j=0;j<n;j++)
packs(value[j],value[j],m,num[j]);
for(i=1;i<=m;i++)
if(dp[i]>0)
cnt++;
cout<<cnt<<endl;
}
return 0;
}
View Code
Problem : 2844 ( Coins ) Judge Status : Accepted
RunId : 23886175 Language : C++
Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Beta
RunId : 23886175 Language : C++
Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Beta
#include<iostream> #include<algorithm> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<string> #include<queue> #include<map> #include<math.h> using namespace std; const int inf=0x3f3f3f3f; const int maxn=1e5+10; int dp[maxn],value[110],num[110]; int max(int a,int b) { return a>b?a:b; } //每次最大值会更新 void pack01(int v,int h,int m) { for(int i=m;i>=v;i--) dp[i]=max(dp[i],dp[i-v]+h); return ; } void packall(int v,int h,int m) { for(int i=v;i<=m;i++) dp[i]=max(dp[i],dp[i-v]+h); return ; } void packs(int v,int h,int m,int cnt) { if(cnt*v>=m) { packall(v,h,m); return ; } int k=1; while(k<=cnt) { pack01(k*v,k*h,m); //更新物品的比例 cnt-=k; //二进制思路压缩背包物品的数量 k<<1; //bug的地方 } pack01(cnt*v,cnt*h,m); //最后一件 return ; } /* dp[i]:不超过i的合成的最大的钱 */ int main() { int n,m,cnt,i,j; while(cin>>n>>m && n+m) { dp[0]=cnt=0; for(i=1;i<=m;i++) dp[i]=-inf; for(i=0;i<n;i++) cin>>value[i]; for(i=0;i<n;i++) cin>>num[i]; for(j=0;j<n;j++) packs(value[j],value[j],m,num[j]); for(i=1;i<=m;i++) if(dp[i]>0) cnt++; cout<<cnt<<endl; } return 0; }