洛谷 P1858 多人背包 题解

版权声明:随便转载。 https://blog.csdn.net/zhang14369/article/details/82795127

一、题目:

洛谷原题

二、思路:

在01背包的基础上加一维k,即 f [ i ] [ j ] [ k ] f[i][j][k] 表示前i件物品,体积为j的k次优解。

那么我们考虑怎样转移。

我们当前有两个序列,一列是不选当前物品,另一列是选当前物品,而且这两个序列是有序的。所以我们可以使用归并排序的思路,进行转移。

可以省掉i那一维。

附(张琪老师):
djkls

口头说不太能说清楚,看代码就明白了。

三、代码:

#include<iostream>
#include<cstdio>
#include<cstring>

#define LL long long
#define FILEIN(s) freopen(s".in","r",stdin)
#define FILEOUT(s) freopen(s".out","w",stdout)
#define FILE(s) FILEIN(s);FILEOUT(s)
#define mem(s,v) memset(s,v,sizeof(s))

using namespace std;
template<class Type>
inline void read(Type &num){
    Type x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    num=f*x;
}

const int maxn=205,maxk=55,maxv=5005;

int K,v,n;
int W[maxn],V[maxn];//体积,价值

int f[maxv][maxk];

LL ans;

int main(){
    mem(f,0xcf);
    read(K);read(v);read(n);
    for(register int i=1;i<=n;++i){
        read(W[i]);read(V[i]);
    }
    f[0][1]=0;
    for(register int i=1;i<=n;++i){
        for(register int j=v;j>=W[i];--j){
            int t1=1,t2=1,len=0,tmp[maxk]={0};
            while(t1+t2<=K+1){
//				f[j]=max(f[j],f[j-W[i]]+V[i]); 这是原本的转移方程。
                if(f[j][t1]>f[j-W[i]][t2]+V[i]){
                    tmp[++len]=f[j][t1++];
                }
                else{
                    tmp[++len]=f[j-W[i]][t2++]+V[i];
                }
            }
            for(register int k=1;k<=K;++k){
                f[j][k]=tmp[k];
            }
        }
    }
    for(register int k=1;k<=K;++k){
        ans+=(LL)f[v][k];
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhang14369/article/details/82795127
今日推荐