[XJOI]noip43 T2多人背包

多人背包

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

输入格式:

第一行有三个整数:K、V、N。
第二行开始的 N 行,每行有两个整数,分别代表这件物品的体积和价值。

输出格式:

只需输出一个整数,即在满足以上要求的前提下所有物品的总价值的最大值。

样例输入:

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

样例输出:

57

数据范围:

总人数 K<=50。
每个背包的容量 V<=5000。
物品种类数 N<=200。
其它正整数都不超过 5000。
输入数据保证存在满足要求的方案。

解题思路:

读完题目,大概学过的人都知道是背包,只是具体怎么做的问题

***如果没学过背包问题的人,一定要去学学,这个是dp的基础,建议学习《背包九讲》

如果是单纯的01背包,f[j]=f[j-a[i]]+v[i]

那么这样只能计算最优解,如果要计算k优解呢?

我们可以增加一维,来记录当前状态下,即装了j的空间的时候的k优解

那么我们的转移就有点问题了,如何将f[j-a[i]]这样一个vector转化到f[j]这个vector

这里我们要提到归并排序,把两个有序数组合并的方法

***如果不会把两个有序数组合并的,也建议先去学习一下,这也是联赛的基础

那么这里便是把f[j]和f[j-a[i]]两个有序vector合并了

%:pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int N=5010,K=100;
int k,v,n,ans;
int a[N],va[N],res[K],f[N][K];
int main(){
    scanf("%d%d%d",&k,&v,&n);
    for (int i=1;i<=n;++i)
        scanf("%d%d",&a[i],&va[i]);
    for (int i=0;i<=v;++i)
        for (int j=0;j<=k+10;++j)
            f[i][j]=-1;
    f[0][1]=0;
    for (int i=1;i<=n;++i)
        for (int j=v;j>=a[i];--j)
            if (f[j-a[i]][1]!=-1){
                int l1=1,l2=1,tot=0;
                while (l1<=k&&l2<=k){
                    if (f[j][l1]==-1||f[j-a[i]][l2]==-1) break;
                    if (f[j][l1]>=f[j-a[i]][l2]+va[i])
                        res[++tot]=f[j][l1],l1++;
                        else res[++tot]=f[j-a[i]][l2]+va[i],l2++;
                }
                if (f[j][l1]==-1)
                    while (l2<=k&&f[j-a[i]][l2]!=-1) res[++tot]=f[j-a[i]][l2]+va[i],l2++;
                     else if (f[j-a[i]][l2]==-1)
                        while (l1<=k&&f[j][l1]!=-1) res[++tot]=f[j][l1],l1++;
                for (int l=1;l<=min(tot,k);++l) f[j][l]=res[l];
            }
    for (int i=1;i<=k;++i)
        ans+=f[v][i];
    printf("%d",ans);
}

总结:这道也算是背包问题的一点拓展,当然还有更多的问题等着读者去解决

时间: 2024-11-12 05:05:28

[XJOI]noip43 T2多人背包的相关文章

P1858 多人背包

P1858 多人背包 题目描述 求01背包前k优解的价值和 要求装满 调试日志: 初始化没有赋给 dp[0] Solution 首先补充个知识点啊, 要求装满的背包需要初始赋 \(-inf\), 边界为 \(dp[0] = 0\) 第 \(k\) 优解的01背包 以 \(dp[j][k]\) 表示 容量为 \(j\) 的背包的第 \(k\) 优解 用到了归并排序的思想 对于第 \(i\) 个物品, 容量为 \(j\), 我们有两种选择: 选第 \(i\) 个物品 不选第 \(i\) 个物品 对于

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

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

洛谷 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,用

20181019测试:T2牛人

这是一道很水的模拟题 只要你知道了算法思路,代码是很好打出来的. 题意解析: 本题的题目看似复杂,但其实可以总结为一句话: 对于任意一个人(比如说你),如果有一个人的一个能力值比你高,那么只要保证你自己的另一个能力不小于他,那么你就是牛人. 算法思路: 知道了这一点后,我们就可以将所有人以其中一个能力作为关键词排序,再将第一个能力相同的人以另一种能力作为关键词排序. bool cmp(People a,People b) { if(a.a!=b.a) { return a.a<b.a; } re

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()

[XJOI]noip40 T2统计方案

统计方案 小B写了一个程序,随机生成了n个正整数,分别是a[1]..a[n],他取出了其中一些数,并把它们乘起来之后模p,得到了余数c.但是没过多久,小B就忘记他选了哪些数,他想把所有可能的取数方案都找出来.你能帮他计算一下一共有多少种取数方案吗?请把最后的方案数模1000000007后输出.小B记得他至少取了一个数. 输入格式: 第一行三个正整数n,p,c,含义如题目所述.接下来一行有n个正整数,表示生成的n个随机数. 输出格式: 一个数,方案数模1000000007. 样例输入: 2 7 2