P1858 多人背包

P1858 多人背包

题目描述
求01背包前k优解的价值和
要求装满



调试日志: 初始化没有赋给 dp[0]


Solution

首先补充个知识点啊, 要求装满的背包需要初始赋 \(-inf\), 边界为 \(dp[0] = 0\)
第 \(k\) 优解的01背包
以 \(dp[j][k]\) 表示 容量为 \(j\) 的背包的第 \(k\) 优解
用到了归并排序的思想
对于第 \(i\) 个物品, 容量为 \(j\), 我们有两种选择:

  1. 选第 \(i\) 个物品
  2. 不选第 \(i\) 个物品

对于 \(1-k\) 中的每一个解做抉择, 我们可以得到 \(2k\) 种答案
由于答案分两边(选或不选)内部有序, 归并得到前 \(k\) 优即可
复杂度 \(O(nmk)\)

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#define LL long long
#define REP(i, x, y) for(int i = (x);i <= (y);i++)
using namespace std;
int RD(){
    int out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const int maxn = 10019;
int K, V, num;
int w[maxn], v[maxn];
int temp[maxn];
int dp[maxn][119];
int main(){
    K = RD(), V = RD(), num = RD();
    REP(i, 1, num)w[i] = RD(), v[i] = RD();
    REP(i, 0, V)REP(k, 1, K)dp[i][k] = -1e9;
    dp[0][1] = 0;
    REP(i, 1, num){
        for(int j = V;j >= w[i];j--){
            int p1 = 1, p2 = 1, cnt = 0;
            while(cnt <= K){
                if(dp[j][p1] > dp[j - w[i]][p2] + v[i])temp[++cnt] = dp[j][p1++];
                else temp[++cnt] = dp[j - w[i]][p2++] + v[i];
                }
            REP(k, 1, K)dp[j][k] = temp[k];
            }
        }
    int ans = 0;
    REP(i, 1, K)ans += dp[V][i];
    printf("%d\n", ans);
    return 0;
    }

原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9858413.html

时间: 2024-10-11 08:01:17

P1858 多人背包的相关文章

洛谷 P1858 多人背包

求01背包前k优解的价值和 输入输出格式 Input/output 输入格式:第一行三个数K.V.N(k<=50,v<=5000,n<=200)接下来每行两个数,表示体积和价值输出格式:前k优解的价值和 解题思路: 这个题刚开始没做出来只能说是因为我没有认真地去看那个叫背包九讲的东西(这里附网址 http://wenku.baidu.com/view/519124da5022aaea998f0f22.html) 背包九讲中第九讲明确给出求次小值及第k小值的办法,做两个队列,b1,b2,用

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[]记录,最后

[XJOI]noip43 T2多人背包

多人背包 DD 和好朋友们要去爬山啦!他们一共有 K 个人,每个人都会背一个包.这些包的容量是相同的,都是 V.可以装进背包里的一共有 N 种物品,每种物品都有给定的体积和价值.在 DD 看来,合理的背包安排方案是这样的:1. 每个人背包里装的物品的总体积恰等于包的容量. 2. 每个包里的每种物品最多只有一件,但两个不同的包中可以存在相同的物品. 3. 任意两个人,他们包里的物品清单不能完全相同. 在满足以上要求的前提下,所有包里的所有物品的总价值最大是多少呢? 输入格式: 第一行有三个整数:K

RQNOJ123_多人背包_C++_Pascal

题目:http://www.rqnoj.cn/problem/123 不得不说,RQNOJ 的机子跑得好慢呀,5*107 的数据范围本地跑 0.2s,服务器上愣是把我卡掉了,最后只好写了一份 Pascal 交上去 本地跑 OJ上跑  咳咳,言归正传 普通的背包是求出最优的那一钟方案,方程转移是 f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]),相当于把 2 个变量经比较后丢到 1 个变量里,也就是 k=1时的情况 而现在我们需要求最优的前 k 组方案,那么可以

vijos1412 多人背包

01背包+归并 看的题解  https://vijos.org/p/1412/solution #include<cstdio> #include<cstring> using namespace std; int a[205]; int b[205]; int f[5005][55]; int k,n,v; void work(int *aa,int *bb,int c) { int t[105]; int ti=1; int ai=1; int bi=1; while(ai+b

【动态规划】【归并】Vijos P1412 多人背包

题目链接: https://vijos.org/p/1412 题目大意: 求01背包的前K优解,要求必须装满(1<=K<=50 0<=V<=5000 1<=N<=200) 题目思路: [动态规划] f[j][k]表示花费为j的第k优解. 合并的过程用归并. 1 // 2 //by coolxxx 3 ////<bits/stdc++.h> 4 #include<iostream> 5 #include<algorithm> 6 #in

cogs 53 多人背包

/* 要求每个最优 即累加前k优解 注意不用去重 */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 210 #define maxm 5010 #define maxk 60 using namespace std; int n,m,k,w[maxn],v[maxn],f[maxm][maxk]; int x[maxk],y[maxk],a,b,z,ans; int init()

【luoguP1858】多人背包

链接 对于每个状态\(f[j]\)多记录一个维度,转移的时候利用类似于归并排序的方法合并,以保证时间复杂度可以承受 注意事项:前\(K\)大可以有重复的价值,法规的卫生费破口还给你 #include<iostream> #include<cstring> #include<cstdio> using namespace std; const int MAXK=55; const int MAXN=210; const int MAXV=5010; inline int

LuoguP1858 多人背包(DP)

第\(K\)优解这类问题可在\(DP\)过程中通过添维解决.归并出当前前\(K\)大的解. #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <cmath> #define R(a,b,c) for(register int a = (b); a <= (c); ++a