【笔记】背包九讲-整合版

原版

背包问题九讲 2.0 alpha1 崔添翼 (Tianyi Cui, a.k.a. dd_engi)

背包九讲学习笔记 第一讲 01背包
背包九讲学习笔记 第二讲 完全背包问题
背包九讲学习笔记 第三讲 多重背包
背包九讲学习笔记:第四讲-混合三种背包问题 第五讲-二维费用的背包问题
背包九讲学习笔记 第六讲-分组的背包问题
背包九讲学习笔记 第七讲-有依赖的背包问题 第八讲-泛化物品
背包九讲学习笔记 第九讲 背包问题问法的变化

1. 01背包

有N件物品和一个容量为V 的背包。放入第i件物品耗费的空间是Ci,得到的价值是Wi。求解将哪些物品装入背包可使价值总和最大。

for(int i=1;i<=n;i++)
	for(int j=v;j>=volume[i];j--)
		dp[j]=max(dp[j],dp[j-volume[i]]+value[i]);

满包问题
初始化为0,max变为加

2. 完全背包

有N种物品和一个容量为V 的背包,每种物品都有无限件可用。放入第i种物品的耗费的空间是Ci,得到的价值是Wi。求解:将哪些物品装入背包,可使这些物品的耗费的空间总和不超过背包容量,且价值总和最大。

for(int i=1;i<=n;i++)
	for(int j=volume[i];j<=v;j++)
    	dp[j]=max(dp[j],dp[j-volume[i]]+value[i]);

3. 多重背包

二进制优化

		int v=read(), n=read();
		int dp[M]={}; //dp[j]表示j体积能装的最大价值, 已经空间优化
		for(int i=1; i<=n; ++i)
		{
			int vol=read(), val=read(), num=read(); //体积,价值,数量
			for(int k=1; k<num; num-=k,k<<=1)
				for(int j=v; j>=k*vol; --j)
					dp[j] = max(dp[j], dp[j-k*vol]+k*val);
			for(int j=v; j>=num*vol; --j)
				dp[j] = max(dp[j], dp[j-num*vol]+num*val);
		}

单调优化

		int v=read(), n=read();
		int dp[M]={};

		for(int i=1; i<=n; ++i)
		{
			int vol=read(), val=read(), num=read(); //体积,价值,数量
			for(int k=0; k<vol; ++k) //枚举体积的余数
			{
				int a[M], b[M], l=0, r=0; //下标, 值, 队头, 队尾, 左闭右开
				for(int j=k; j<=v; j+=vol)
				{
					int y = dp[j] - j/vol*val; //当前体积的贡献值

					while(l<r && y>=b[r-1]) r--; //入队
					a[r] = j; b[r++] = y;

					while(a[l]<j-num*vol) ++l; //出队

					dp[j] = b[l] + j/vol*val; //选择最大值
				}
			}
		}
		printf("%d\n",dp[v] );

4. 混合三种背包

可以都按多重解,设置好件数就行。

5. 二维费用背包

二维费用的背包问题是指:对于每件物品,具有两种不同的空间耗费,选
择这件物品必须同时付出这两种代价。对于每种代价都有一个可付出的最大值
(背包容量)。问怎样选择物品可以得到最大的价值。
设这两种代价分别为代价一和代价二,第i件物品所需的两种代价分别
为Ci和Di。两种代价可付出的最大值(两种背包容量)分别为V 和U。物品的
价值为Wi。

新加的一维一般为件数,注意遍历顺序要写对。

    for(int i=1;i<=n;i++)
        for(int j=v;j>=volume[i];j--)
            for(int k=w;k>=weight[i];k--)
                dp[j][k]=max(dp[j][k],dp[j-volume[i]][k-weight[i]]+value[i]);

cty : 当发现由熟悉的动态规划题目变形得来的题目时,在原来的状态中加一维
以满足新的限制是一种比较通用的方法。希望你能从本讲中初步体会到这种方
法。

6. 分组背包

有N件物品和一个容量为V 的背包。第i件物品的费用是Ci,价值是Wi。这
些物品被划分为K组,每组中的物品互相冲突,最多选一件。求解将哪些物品
装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

遍历顺序kji

for(int k=1;k<=p;k++) 
	for(int j=v;j>=0;j–) //此处遍历顺序与物品种类有关 
		for(int i:part[k]) 
			dp[j]=max(dp[j],dp[j-volume[i]]+value[i]). 

8.泛化物品

考虑这样一种物品,它并没有固定的费用和价值,而是它的价值随着你分
配给它的费用而变化。这就是泛化物品的概念。

泛化物品的和:
f v = m a x k = 0 v ( h k + l v − k ) f_v = max_{k=0}^v(h_k + l_{v − k} ) fv=maxk=0v(hk+lvk)

7.有依赖的背包问题

这种背包问题的物品间存在某种“依赖”的关系。也就是说,物品i依赖于
物品j,表示若选物品i,则必须选物品j。为了简化起见,我们先设没有某个物
品既依赖于别的物品,又被别的物品所依赖;另外,没有某件物品同时依赖多
件物品。

确定每组物品的主件k后,对主件k的“附件集合”先进行一次01背包,求得主件k的物品组泛化物品。再利用分组背包来求解。

9. 背包问题问法的变化

输出方案
输出字典序最小的方案
求方案数
求最优方案数
求第k优解

留坑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值