3 10 1 2 4 2 1 1 2 5 1 4 2 1 0 0
8 4
比较单纯的多重背包,用二进制去优化硬币对饮的面值就行了。然后对包进行判断有多少个符合 b[i] == i即可;
a[i]表示钱币的价值,b[i]表示钱币的数量。
#include <iostream> #include <algorithm> using namespace std; #define M 100005 int dp[M],vis[M]; //想用01背包做,果断超时。。。 int a[105],b[105]; int n,tot,m; int max(int x,int y) { return x>y?x:y; } //百度所得,膜拜。 void CompletePack(int cost,int weight) //如果取不完就是完全背包。 { for(int i=cost;i<=m;i++) dp[i]=max(dp[i],dp[i-cost]+weight); } void ZeroOnePack(int cost,int weight) //如果能取完就是01背包。 { for(int i=m;i>=cost;i--) dp[i]=max(dp[i],dp[i-cost]+weight); } void MultiplyPack(int cost,int weight,int amount) //多重背包。 { if(cost*amount>=m) //取不完。 CompletePack(cost,weight); else { int k=1; while(k<amount) { ZeroOnePack(k*cost,k*weight); //传说中的二进制优化,表示没明白。我觉得就是一次取1,2,4,8。。。枚钱币,倍增的思想。 amount-=k; k<<=1; } ZeroOnePack(amount*cost,amount*weight); //这里把剩下的再算上去。 } } int main(int i,int j,int k) { while(scanf("%d%d",&n,&m)!=EOF&&n&&m) { tot=k=0; for(i=1;i<=n;i++) scanf("%d",&a[i]); for(i=1;i<=n;i++) scanf("%d",&b[i]); memset(dp,0,sizeof(dp)); for(i=1;i<=n;i++) MultiplyPack(a[i],a[i],b[i]); for(i=1;i<=m;i++) if(dp[i]==i) tot++; printf("%d\n",tot); } return 0; }
HDU 2844 Coins (动规),布布扣,bubuko.com
原文:http://blog.csdn.net/qq2256420822/article/details/38023891