背包问题

posted on 2019-08-27 19:16:24

多重背包

题目描述 Description

你有一个容量为 \(M\) 的背包,和 \(N\) 种物品。

每种物品都有三个属性,\(v_i,w_i,c_i\),分别表示这种物品的体积、价值和件数。

你的任务是,从这些所给物品中,选出若干件,其体积之和不能超过背包容量,并且使所选物品的权值的和最大。

输入描述 Input Description

第一行两个整数\(N,M\)

接下来 \(N\) 行每行三个数\(v_i,w_i,c_i\)描述第 \(i\) 件物品的属性

输出描述 Output Description

最大的权值和

样例输入 Sample Input

2 8
2 100 4
4 100 2

样例输出 Sample Output

400

数据范围及提示 Data Size & Hint

对于20%的数据,\(c_i=1\)

对于60%的数据,\(N,M \leq 500,c_i \leq 100\)

对于90%的数据,\(N,M \leq 3000\)

对于100%的数据 , \(N,M \leq 7000,c_i \leq 5000\),保证答案不超过 \(2147483647\)

  • tip:

  • 有多重背包的题目,数组一定要开大!!!!!!

  • 不然会 WA 而不是 RE .

题解1:

int n,m,tot;
int f[7010],p[100010],v[100010],w[100010];
int main()
{
	cin >> n >> m;
	for(int i=1; i<=n; i++)
		cin >> w[i] >> v[i] >> p[i];
	for(int i = 1; i <= n; i++) {
		int num = min(p[i], m / w[i]);
		for(int k = 1; num > 0; k <<= 1) {
			if (k > num) k = num;
			num -= k;
			for(int j = m; j >= w[i] * k; j--)
				f[j] = max(f[j], f[j - w[i] * k] + v[i] * k);
		}
	}
	cout << f[m];

题解2:

int n,m,tot;
int f[7010],c[100010],v[100010];
int main() 
{
	cin >> n >> m;
	for(int i=1;i<=n;i++) {
		int x,y,z;
		cin >> x >> y >> z;
		int base=1;
		while(z>=base) {
			c[++tot]=x*base;
			v[tot]=y*base;
			z-=base;
			base<<=1;
		}
		if(z>0) {
			c[++tot]=z*x;
			v[tot]=z*y;
		}
	}
	for(int i=1;i<=tot;i++)
		for(int j=m;j>=c[i];j--)
			f[j]=max(f[j],f[j-c[i]]+v[i]);
	cout << f[m];

混合背包

题目描述

\(n\) 种物品和一个容量是 \(m\) 的背包。

物品一共有三类:

  • 第一类物品只能用 \(1\) 次(\(01\) 背包);
  • 第二类物品可以用无限次(完全背包);
  • 第三类物品最多只能用 \(s_i\) 次(多重背包)。

每种物品体积是 \(w_i\),价值是 \(v_i\)。求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。输出最大价值。

输入格式

从标准输入读入数据。

第一行两个整数 \(n\)\(m\)\(0 \leq v_i,w_i \leq 1000\)),用空格隔开,分别表示物品种数和背包容积。

接下来有 \(n\) 行,每行三个整数 \(w_i,v_i\)\(0 \leq w_i,v_i \leq 1000\))和 \(s_i\)\(-1 \leq s_i \leq 1000\)),用空格隔开,分别表示第 \(i\) 种物品的体积、价值和数量。

  • \(s_i = -1\) 表示第 \(i\) 种物品只能用 \(1\) 次;
  • \(s_i = 0\) 表示第 \(i\) 种物品可以用无限次;
  • \(s_i > 0\) 表示第 \(i\) 种物品可以使用 \(s_i\) 次。

输出格式

输出到标准输出。

输出一个整数,表示最大价值。

样例1输入

4 5
1 2 -1
2 4 1
3 4 0
4 5 2

样例1输出

8

题解:

int n,m,v[10000],w[10000],s[10000],a,b,c,f[10000];
int main()
{
	int num=1;
	cin >> n >> m;
	for(int i=1;i<=n;i++)
	{
		cin >> a >> b >> c;
		if(c>0)
		{
			int base = 1;
			while(c>=base)
			{
				w[num]=a*base;
				v[num]=b*base;
				s[num++]=-1;
				c-=base;
				base*=2;
			}
			if(c>0)
			{
				w[num]=a*c;
				v[num]=b*c;
				s[num++]=-1;
			}
		}
		else
		{
			w[num]=a;
			v[num]=b;
			s[num++]=c;
		}
	}
	for(int i=1;i<=num-1;i++)
	{
		if(s[i]==0)
		{
			for(int j=w[i];j<=m;j++)
				f[j]=max(f[j-w[i]]+v[i],f[j]);
		}
		else 
		{
			for(int j=m;j>=w[i];j--)
				f[j]=max(f[j-w[i]]+v[i],f[j]);
		}
	}
	cout << f[m];
posted @ 2019-11-06 06:04  Atoposyz  阅读(129)  评论(0编辑  收藏  举报