• [洛谷P1858] 多人背包


    洛谷题目链接:多人背包

    题目描述

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

    输入输出格式

    输入格式:

    第一行三个数K、V、N

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

    输出格式:

    前k优解的价值和

    输入输出样例

    输入样例#1:

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

    输出样例#1:

    57

    说明

    对于100%的数据, (Kle 50,Vle 5000,Nle 200)

    题意已经很清楚了,就不多赘述了.

    题解:
    首先考虑一下如何做01背包.显然有$$f[j]=max(f[j], f[j-cost[i]]+value[i])$$.那么我们应该如何记录这个前(k)优的解呢?

    首先是应该想到将前(k)优的解加入状态的转移中.先定义状态(f[j][k])表示(j)的容量的第(k)优解的值.考虑一下转移的情况,显然(f[j][k])的情况只能由(f[j][k])(f[j-cost[i]][1...k])转移而来(其实这个(1...k)是一个确定的值,因为(k)越大,(f[j-cost[i]][1...k])越小,也就是说这个是单调的.肯定只有一个值能转移到(f[j][k])的状态).

    那么既然这个是单调的,并且又只有两种决策,那么其实这里是可以用归并来求解最大值的.在枚举的时候,可以用两个指针记录已经转移到第几个状态.每次选择大的那一个,最后归并回原数组(这里我是一边枚举一边归并的).

    #include<bits/stdc++.h>
    using namespace std;
    const int V=5000+5;
    const int N=200+5;
    const int K=50+5;
    
    int n, v, k, c[N], w[N], q[K], ans = 0;
    int f[V][K];
    
    int main(){
        cin >> k >> v >> n;
        memset(f, 128, sizeof(f)); f[0][1] = 0;
        for(int i=1;i<=n;i++) cin >> c[i] >> w[i];
        for(int i=1;i<=n;i++)
    		for(int j=v;j>=c[i];j--){
    		    int now = 1, last = 1, cnt = 0;
    		    while(cnt < k){
    				if(f[j][now] > f[j-c[i]][last]+w[i])
    				    q[++cnt] = f[j][now++];
    				else q[++cnt] = f[j-c[i]][last++]+w[i];
    		    }
    		    for(int o=1;o<=k;o++) f[j][o] = q[o];
    		}
        for(int i=1;i<=k;i++) ans += f[v][i];
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Python第二十天 shutil 模块 zipfile tarfile 模块
    SQL Server中SET QUOTED_IDENTIFIER的使用
    SQL Server AG集群启动不起来的临时自救大招
    检查使用共享表空间的表
    数据库历史简图
    线上centos6出现软死锁 kernel:BUG: soft lockup
    ORA-01810:格式代码出现两次 解决方法
    C# DES (ECB模式) 加密解密 --单倍长
    Android-ContentProvider使用
    第十三周(动物这样叫)
  • 原文地址:https://www.cnblogs.com/BCOI/p/9057560.html
Copyright © 2020-2023  润新知