[背包变形] P1858 多人背包

链接https://www.luogu.com.cn/problem/P1858.

题目描述

求01背包前k优解的价值和

DD 和好朋友们要去爬山啦!

他们一共有 K 个人,每个人都会背一个包。这些包 的容量是相同的,都是 V。可以装进背包里的一共有 N 种物品,每种物品都有 给定的体积和价值。

在 DD 看来,合理的背包安排方案是这样的: 每个人背包里装的物品的总体积恰等于包的容量。 每个包里的每种物品最多只有一件,但两个不同的包中可以存在相同的物品。

任意两个人,他们包里的物品清单不能完全相同。 在满足以上要求的前提下,所有包里的所有物品的总价值最大是多少呢?

输入格式

第一行三个数K、V、N

接下来每行两个数,表示体积和价值

输出格式

前k优解的价值和

输入 #1

2 10 5
3 12
7 20
2 4
5 6
1 1

输出 #1

57

说明/提示

对于100%的数据,K≤50,V≤5000,N≤200

过程

看到这题一脸懵 然后看题解 发现了背包9讲然后又去研究 发现有点高深 又去百度 找到了几篇较为通俗易懂的讲解背包的博客 然后算是稍微入了入门

这题是第k优解的背包问题 算是背包的变形 首先这题需要了解01背包的原理 已经01背包的一维表达 即:f[i]=max(f[i],f[i-w[i]+v[i]);
通过01背包的基本知识 我们知道*f[i]的决定因素只有f[i]f[i-w[i]+v[i]*所以增加一维k代表第k优解 那么f[i][k]是在i容量下的第k优解的值 那么f[i][1]->f[i][k]是呈单调的序列且f[i][1]是最优解

此时我们设变量a1,a2来分别表示第a1优解和第a2优解
a1指代f[i],a2指代f[i-w[i]+v[i]时 然后引用背包九讲中的一句话:一个正确的状态转移方程的求解过程遍历了所有可用的策略,也就覆盖了问题的所有方案 所以在这个过程中 较大的存入一个数组中保存 并使该k+1 因为在之前的状态中每次保存是最优的前n个(背包基础知识) 所以在后面的检测中 按照背包的一个物品一个物品选择 会不断更新最好的结果 也就可以获得前k(指人数的k)最优解 相加即为最有解

注意!!!
背包问题初始值选择 参考背包9讲或者直接搜索

代码

#include<bits/stdc++.h>
using namespace std;

int v,k,n,T=0;
int f[5005][55],w[205],c[205],t[55];

int main(){
	cin>>k>>v>>n;
	for(int i=1;i<=n;i++)
		cin>>w[i]>>c[i];
	for(int i=0;i<=5000;i++){
		for(int j=0;j<=50;j++){
			f[i][j]=-1999999;
		}
	}
	f[0][1]=0;
	for(int i=1;i<=n;i++){
		for(int j=v;j>=w[i];j--){
			int a1=1,a2=1,total=0;
			while(total<=k){
				if(f[j][a1]>f[j-w[i]][a2]+c[i])
					t[++total]=f[j][a1++];
				else
					t[++total]=f[j-w[i]][a2++]+c[i];
			}
			for(int x=1;x<=k;x++)
				f[j][x]=t[x];
		}
	}
	for(int i=1;i<=k;i++)
		T+=f[v][i];
	cout<<T;
	return 0;	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值