我的学习记录:完全背包和多重背包(背包九讲)(二进制优化)

我的学习记录:完全背包和多重背包(背包九讲)(二进制优化)


前言

😃 这篇博客是我的第二篇博客,距离我学习完简单的01背包、写完笔记的时候已经有一段时间了,中间摸鱼太多了,目前背包的学习进度有点慢了,立个flag看下能多就写完呢


提示:以下是本篇文章正文内容

一、题目引入- Buns

题目:
Lavrenty, a baker, is going to make several buns with stuffings and sell them.

Lavrenty has n grams of dough as well as m different stuffing types. The stuffing types are numerated from 1 to m. Lavrenty knows that he has ai grams left of the i-th stuffing. It takes exactly bi grams of stuffing i and ci grams of dough to cook a bun with the i-th stuffing. Such bun can be sold for di tugriks.

Also he can make buns without stuffings. Each of such buns requires c0 grams of dough and it can be sold for d0 tugriks. So Lavrenty can cook any number of buns with different stuffings or without it unless he runs out of dough and the stuffings. Lavrenty throws away all excess material left after baking.

Find the maximum number of tugriks Lavrenty can earn.

输入:
The first line contains 4 integers n, m, c0 and d0 (1 ≤ n ≤ 1000, 1 ≤ m ≤ 10, 1 ≤ c0, d0 ≤ 100). Each of the following m lines contains 4 integers. The i-th line contains numbers ai, bi, ci and di (1 ≤ ai, bi, ci, di ≤ 100).

输出
Print the only number — the maximum number of tugriks Lavrenty can earn.

样例
Input
10 2 2 1
7 3 2 100
12 3 1 10
Output
241

Input
100 1 25 50
15 5 20 10
Output
200

大概说明下题意:你刚开始有n克面粉、m份包子的制作方法;你可以选择不要馅来制作馒头(花费c0、价值d0),或者制作包子:下面m行,每行的第一个a时这种馅的总量(克)、制作一个这样的馅花费b克馅、同时花费c克面粉、制造的价值是d;问最终的最大价值是多少?

二、学习

引入

开门见山

1.完全背包

完全背包相对于01背包最大的区别在于他的i件物品是不是无限的,如果可以放无限个那么显然01背包是解决不了这类问题的,于是我们得出多重背包方程下面直接上代码吧,看看详细的分析能不能以后补上之类的。

代码如下(示例):

	for(int i = 1; i < n; i++)
	{
		for(int j = v[i]; j <= m; j++)
		{
			f[j]=max(f[j],f[j-v[i]+w[i]);
		}
	}

	cout << f[m] << endl;//最终答案。
//n是物品的种类,m是背包的大小,数组v是存储背包的体积,数组w是物体的价值。

2.多重背包

多重背包的问题区别于01背包和完全背包,当i类物品的种类只有s件时,我们可以把它看作很多零一背包的问题,但是件数回导致程序的时间复杂度上升,所以我们可以采用一种二进制优化的方式来处理此类问题。

代码如下(示例)(二进制优化):

	int num = 1, v, w, s;//num代表序号。
	for(int i = 1; i <= m; i++)//m时物品的种类。
	{
		cin >> v >> w >> s;
		//分别输入v(体积)、w(价值)、s(件数)。
		for(int j = 1; j <= s; j<<=1)
		{
			v[num] = j*v;
			w[num++] = j*w;
			s-=j;	
		} 
		if(s)
		{
			v[num] = s*v;
			w[num++] = s*w;
		}
	}//二进制优化 

多重背包的代码(01背包)

	for(int i = 1; i < num; i++)
	{
		for(int j = n; j >= v[i]; j--)//注意倒叙
		{
			f[j] = max(f[j], f[j-v[i]]+w[i]);
		} 
	}

总结

我的B题也在写的时候错误很多,其中WA最多的就是处理完全背包部分的时候对于第二层循环的初始赋值条件错误。之所以很慢,是因为检查出来时因为样例过了,甚至过到了test23,我天真的以为时数组越界或者较大数据出现的错误。

下面我把自己的AC代码贴上:

#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#include <math.h>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll N = 10000000+10;

ll n, m, c0, d0, a, b, c, d;
ll v[N], w[N], f[N]; 

int main (void)
{
	cin >> n >> m >> c0 >> d0;
	//n表示的是背包大小,m是物品种类,c0一种初始物品的体积,d0初始物品的价值; 
	int num = 1;
	for(int i = 1; i <= m; i++)
	{
		cin >> a >> b >> c >> d;
		int s = a/b;
		//a表示了馅的总量,b表示每份馅用量,c表示用的面粉(背包),d表示的是价值;
		for(int j = 1; j <= s; j<<=1)
		{
			v[num] = j*c;
			w[num++] = j*d;
			s-=j;	
		} 
		if(s)
		{
			v[num] = s*c;
			w[num++] = s*d;
		}
	}//二进制优化 
	
//	for(int i = 1; i < num; i++)
//	{
//		cout << v[i] << " " << w[i] << " " << num << endl;
//	}//观察二进制优化结果 

	for(int i = 1; i < 2; i++)
	{
		for(int j = c0; j <= n; j++)
		{
			f[j]=max(f[j],f[j-c0]+d0);
		}
	}//完全背包处理
	
	for(int i = 1; i < num; i++)
	{
		for(int j = n; j >= v[i]; j--)
		{
			f[j] = max(f[j], f[j-v[i]]+w[i]);
		} 
	}//多重背包的处理(01方式)
	

	
	cout << f[n] << endl;
//	ll res = 0;
//	for(int i = 1; i <= n; i++) res = max(res, f[i]);
//	cout << res << endl;
	
	
	return 0;
}
//powered by xiaodezi
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值