【9928】混合背包

Time Limit: 1 second
Memory Limit: 128 MB

【问题描述】

一个旅行者有一个最多能用V公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn。
有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包)。
求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
【样例解释】
选第一件物品1件和第三件物品2件。 

【输入格式】

第一行:二个整数,V(背包容量,V<=200),N(物品数量,N<=30);
第2..N+1行:每行三个整数Wi,Ci,Pi,前两个整数分别表示每个物品的重量,价值,第三个整数若为0,则说明此物品可以购买无数
件,若为其他数字,则为此物品可购买的最多件数(Pi)。

【输出格式】

仅一行,一个数,表示最大总价值。

Sample Input

10 3
2  1  0
3  3  1
4  5  4





Sample Output

11

【题解】

遇到0的时候j层循环就从w[i]..m进行更新。

遇到不是0就从m..0进行循环。然后再嵌套一层k循环用来枚举放入几个物品。

一定要注意先用j循环再k循环,因为如果先k循环。会无法确定我们更新的值用了几个物品。会可能超过最大上限。

【代码】

#include <cstdio>

int m,n,w[40],c[40],num[40],f[250];

void input_data()
{
	scanf("%d%d",&m,&n);
	for (int i = 1;i <= n;i++) 
		scanf("%d%d%d",&w[i],&c[i],&num[i]);
}

void get_ans()
{
	for (int i = 1;i <= n;i++) //对n个物品进行决策 
		{
			if (num[i] == 0) //如果是完全背包 就要顺序更新 
				for (int j = w[i]; j <= m;j++)
					if (f[j] < f[j-w[i]] + c[i])
						f[j] = f[j-w[i]] + c[i];
			if (num[i] > 0) //如果是多重或01背包就逆序更新。 
				for (int j = m;j >=0;j--)
					for (int k = 1;k <= num[i];k++) //多重背包 
						{
							int ju = j-k*w[i]; //如果不能装下k个物品就跳过。 
							if (ju < 0)
								continue;
							if (f[j] < f[j-k*w[i]] + k *c[i]) //如果能更新解就更新。 
								f[j] = f[j-k*w[i]] + k * c[i];
						}
		}
}

void output_ans()
{
	printf("%d",f[m]);	
}

int main()
{
	//freopen("F:\rush.txt","r",stdin);
	input_data();
	get_ans();
	output_ans();
	return 0;
}


原文地址:https://www.cnblogs.com/AWCXV/p/7632392.html