多人背包
题目描述:求01背包前k优解的价值和
输入格式:第一行三个数k,v,n 接下来n行每行两个数 体积和价值
输出格式:前k优解的价值和
正解:
在01背包的基础上再加上一个维度
f[m][k]:重量为m的第k优解 注意要初始化为-inf 而不是0 因为背包要填满
用tmp[k] 来存当前求的体积为m时的第k优解 最后用它来更新f[m][k]即可
<下面的栗子中用到的数组(也是代码里的数组)>:
a[i] 第i件物品的体积;b[i] 第i件物品的价值
然后以下的转移的外层循环就是一般01背包的循环 具体见代码
假设我们现在要求f[m][k] (k=1,2,…,5)
f[m][1]显然只能为max(f[m][1],f[m-a[i]][1]+b[i])
若f[m][1]=f[m-a[i]]+b[i] 那么f[m][2]=max(f[m][1],f[m-a[i]][2]+b[i])
若f[m][1]=f[m][1] 那么f[m][2]=max(f[m][2],f[m-a[i]][1]+b[i])
以此类推 其实应该还是比较好理解的 但是感觉写好code有一点点难
#include<iostream> #include<algorithm> #include<cstdio> #define go(i,a,b) for(register int i=a;i<=b;i++) #define goo(i,a,b) for(register int i=a;i>=b;i--) #define inf 210000000 using namespace std; int read() { int x=0,y=1;char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();} return x*y; } int k,v,n,t,t1,t2,ans,a[210],b[210],f[5010][60],tmp[60]; int main() { k=read();v=read();n=read(); go(i,1,n) a[i]=read(),b[i]=read(); go(i,0,v) go(j,1,k) f[i][j]=-inf; f[0][1]=0; go(i,1,n) goo(j,v,a[i]) { t1=1;t2=1;t=0; //t1,t2 相当于两个指针吧 具体理解见上面分析中的栗子 while(t<=k) { if(f[j][t1]<f[j-a[i]][t2]+b[i]) tmp[++t]=f[j-a[i]][t2++]+b[i]; else tmp[++t]=f[j][t1++]; } go(x,1,k) f[j][x]=tmp[x]; } go(i,1,k) ans+=f[v][i]; printf("%d",ans); return 0; }
光伴随的阴影