本题的特殊性是价值与重量相等
将第i种物品分成若干件物品,其中每件物品有一个系数,
这件物品的费用和价值均是原来的费用和价值乘以这个系数。
使这些系数分别为1,2,4,…,2^(k-1),n[i]-2^k+1,且k是满足n[i]-2^k+1>0的最大整数。
例如,如果n[i]为13,就将这种物品分成系数分别为1,2,4,6的四件物品。
分成的这几件物品的系数和为n[i],表明不可能取多于n[i]件的第i种物品。
另外这种方法也能保证对于0..n[i]间的每一个整数,均可以用若干个系数的和表示
/* * 2844_1.cpp * * Created on: 2013年7月30日 * Author: Administrator */ #include <iostream> using namespace std; /** * n:物品的种数 * V:限定的价值.在这里可以认为是背包的容量 * c[]:用来保存每种物品的价值 * num[]:用来保存每种物品的数量 * f[v]:表示容量为v是所能获得的最大价值 * */ int f[100005]; int c[105],num[105]; int n,V; void ZeroOnePack(int cost , int weight){ for(int v = V ; v >= cost ; --v){ f[v] = max(f[v],f[v-cost] + weight); } } void CompletePack(int cost , int weight){ for(int v = cost ; v <= V ; ++v){ f[v] = max(f[v],f[v-cost] + weight); } } /** * cost:每种物品所占的体积 * weight:每种物品的价值 * amount:每种物品有多少件 */ void MultiplePack(int cost,int weight , int amount){ if(cost*amount >= V){//当物品总体积>=限制体积时,当成完全背包来解 CompletePack(cost,weight); }else{ int k = 1; while( k < amount ){ ZeroOnePack(k*cost,k*weight); amount -=k; k<<=1; } if(amount>0){ ZeroOnePack(amount*cost,amount*weight); } } } int main(){ while(cin>>n>>V,n||V){ for(int i = 1 ; i <= n ; ++i){ cin >> c[i]; } for(int i = 1 ; i <= n ; ++i ){ cin >> num[i]; } memset(f,0,sizeof(f)); for(int i = 1 ; i <=n ; ++i){ MultiplePack(c[i],c[i],num[i]); } int ans = 0; for(int i = 1 ; i <= V ; ++i){ if(f[i] == i){//如果容量为i是所能获得的最大价值==i ++ans;//所能支付的钱数+1 } } cout<<ans<<endl; } }