多重背包

有N种物品和容量为V的背包,第种i件物品价值v[i],费用w[i],数量num[i]。求解在如何让背包获得最大价值。
基本思路:
可把每种物品拆分,拆分后的几份物品独立。例如把数量为22,价值为v,费用为w的物品拆成5份,每份包含1,2,4,8,7件。1,2,4,8,7可以组合成0~22内的任何数字。所以从这三份物品我们可以得到所有种情况。
二进制拆分
n=22。1,2,4,8可以组合成0~15的任何数
多重背包_第1张图片
1-15内的数和7组合,又可以得到16-22的所有数。

	for(int j=1;j<num[i];j<<=1){
		new_v[cnt]=v[i]*j;
		new_w[cnt++]=w[i]*j;
		num[i]-=j;
	}
	if(num[i]>0) {
		new_v[cnt]=v[i]*num[i];
		new_w[cnt++]=w[i]*num[i];
	}
 *Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. One day Hibix opened purse and found there were some coins. He decided to buy a very nice watch in a nearby shop. He wanted to pay the exact price(without change) and he known the price would not more than m.But he didn't know the exact price of the watch.
You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony's coins of value A1,A2,A3...An then calculate how many prices(form 1 to m) Tony can pay use these coins. 

Input
The input contains several test cases. The first line of each test case contains two integers n(1 ≤ n ≤ 100),m(m ≤ 100000).The second line contains 2n integers, denoting A1,A2,A3…An,C1,C2,C3…Cn (1 ≤ Ai ≤ 100000,1 ≤ Ci ≤ 1000). The last test case is followed by two zeros.
Output
For each test case output the answer on a single line.*
Sample Input

3 10
1 2 4 2 1 1
2 5
1 4 2 1
0 0

Sample Output
8
4

对于这道题拆包后,并不是一个01背包问题。
此题费用和价值同一含义
要组合出背包价值为1~m,并计算可以得到的1~m价值的个数(由
不同的组合法组合相同的值,只计一个)。
从第1件物品开始向后枚举,dp[j]==1表示容量为j的值可以
组合出来,为0表示不可。
预处理dp[w[i]]=1,表示只装w[i]的物品是可以的
在第i件物品时背包容量j,sum=(v1+v2+...+vi), j从sum~w[i]
枚举,dp[j]查询dp[j-w[i]]是否存在,若存在则dp[j]也存在。
递推的方式01背包一样
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1e6;
const double eps=1e-6;
int a[maxn],c[maxn];
int cnt[maxn];
int  dp[maxn];
int main(){
	int n,m;
	while(scanf("%d%d",&n,&m)==2&&(n!=0&&m!=0)){
		memset(dp,0,sizeof dp);
		memset(cnt,0,sizeof cnt);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		for(int i=1;i<=n;i++){
			scanf("%d",&c[i]);
		}	
		int num=1;
		for(int i=1;i<=n;i++){
			for(int j=1;j<c[i];j<<=1){
				cnt[num++]=a[i]*j;
				c[i]-=j;
			}
			if(c[i]>0) cnt[num++]=a[i]*c[i];
		}
        int max = 1;  
        int ans = 0;
        for (int i = 1; i < num; ++i) {
                max+=cnt[i];
                max=min(m,max);
            for (int j = max; j >= cnt[i]; --j) {  
                if(dp[j]) continue;                    
                if(j == cnt[i]) dp[j] = 1;            
                else if(j-cnt[i] > 0 && dp[j-cnt[i]]) dp[j] = 1;
                if( dp[j]) { 
					ans++; 
				}
            }
        }
		cout<<ans<<endl;
	}
	return 0;
}

谨记,这也是一个dp思路
多重背包_第2张图片

你可能感兴趣的:(动态规划,背包问题)