链接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;
}