Luogu P1858 多人背包

gate

求01背包前k优解的价值和(题面还挺亲切的)

本来我想的是直接边跑01背包边记录,最后排序...

然后意识到,这种方法是枚举不全的。

看了眼题解...要多开一维!

k的范围很小,f[i][j]表示空间为i,是第j优解。

那么,因为有许多j,所以对于每个不一样的j,

f[i][j]既可能从f[i-c][...]+w转移过来,也可能从f[i][...]转移过来。

用类似于归并排序的方法:

维护两个指针t1,t2;

同时为了防止新的f覆盖原来的影响后续的状态转移,用一个临时的g[]记录,最后再转移过去。

那么就有g[t] = max(f[j-c][t1++]+w,f[j][t2++])

最后答案统计f[m][1-k]就可以了。

代码如下

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define MogeKo qwq
#define Darcy amour
using namespace std;

const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
int k,m,n,c,w,ans,f[maxn][60],g[60];

int main() {
    scanf("%d%d%d",&k,&m,&n);
    memset(f,-INF,sizeof(f));
    f[0][1] = 0;
    for(int i = 1; i <= n; i++) {
        scanf("%d%d",&c,&w);
        for(int j = m; j >= c; j--) {
            int t1 = 1,t2 = 1;
            for(int t = 1; t <= k; t++) {
                if(f[j-c][t1] + w > f[j][t2])
                    g[t] = f[j-c][t1++] + w;
                else
                    g[t] = f[j][t2++];
            }
            for(int t = 1; t <= k; t++)
                f[j][t] = g[t];

        }
    }
    for(int i = 1; i <= k; i++)
        ans += f[m][i];
    printf("%d",ans);
    return 0;
}
View Code

 

原文地址:https://www.cnblogs.com/mogeko/p/11715703.html