二进制拆分
方法是:将第 i 种物品分成若干件 01 背包中的物品,其中每件物品有一个系
数。这件物品的费用和价值均是原来的费用和价值乘以这个系数。令这些系数分别为
1; 2; 22 : : : 2k-1; Mi - 2k + 1,且 k 是满足 Mi - 2k + 1 > 0 的最大整数。例如,如果 Mi
为 13,则相应的 k = 3,这种最多取 13 件的物品应被分成系数分别为 1; 2; 4; 6 的四件
物品。
分成的这几件物品的系数和为 Mi,表明不可能取多于 Mi 件的第 i 种物品。另外
这种方法也能保证对于 0 : : : Mi 间的每一个整数,均可以用若干个系数的和表示。这里
算法正确性的证明可以分 0 : : : 2k-1 和 2k : : : Mi 两段来分别讨论得出,希望读者自己思
考尝试一下。
将cash作为背包的容量,那么硬币所占背包的体积便是数量*面额,价值也是数量*面额
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <map>
using namespace std;
const int INF=1e9+100;
int w[1005],c[1005];
int d[100005];
int main(){
//freopen("out.txt","w",stdout);
int n,k1;
while(scanf("%d",&n)!=EOF){
scanf("%d",&k1);
int sum=0;
for(int i=0;i<k1;i++){
scanf("%d %d",&w[i],&c[i]);
}
memset(d,0,sizeof(d));
for(int i=0;i<k1;i++){
int m=w[i],k=1;
while(k<m){
for(int j=n;j>=k*c[i];j--){
d[j]=max(d[j],d[j-k*c[i]]+k*c[i]);
}
m-=k;
k*=2;
}
for(int j=n;j>=m*c[i];j--){
d[j]=max(d[j],d[j-m*c[i]]+m*c[i]);
}
}
printf("%d\n",d[n]);
}
return 0;
}