这道题运用了多重背包的思想,所以这里重点讲一下多重背包的做法:
0-1背包只要认真看过《算法竞赛入门经典》的应该已经掌握了。其实首先,我们可以将多重背包问题,转化为0-1背包问题,只要将数量为v的每一种物品“展开”看做v个价值相同的物品,然后用0-1背包的方法去求即可。但是这样肯定会TLE的。运用状态压缩的思想,将每一个容量为v,价值为p的物品转化为几个“权值”为1,2,2^2,……,2^(k-1),v-2^k+1的物品,将p与各项权值相乘得到其容量,将我们用此方法对每一个i得到的这些容量都存入一个数组中。该数组就可以作为一组新的物品,其价值和体积相等。
然后我们用一维数组的0-1背包来做就行了。具体可以再参考《背包问题九讲》。
#include <stdio.h> #include<stdlib.h> int cash,n,d[11],c[11]; int max(int a,int b) { if(a>b) return a; else return b; } int main() { int i,j,k; while(scanf("%d%d",&cash,&n)!=EOF) { k=0; int v[100],dp[100005]={0}; for(i=1;i<=n;i++) { scanf("%d%d",&c[i],&d[i]); j=1; int num=c[i]; while(num>j) { num-=j; v[k++]=d[i]*j; j*=2; } if(num) v[k++]=num*d[i]; } for(i=0;i<k;i++) for(j=cash;j>=0;j--) if(j-v[i]>=0) { dp[j]=max(dp[j-v[i]]+v[i],dp[j]); } printf("%d\n",dp[cash]); } return 0; }