背包的第k优解[动态规划]

From easthong

背包的第k优解

 
     
     
  描述 Description  
  DD 和好朋友们要去爬山啦!他们一共有 K 个人,每个人都会背一个包。这些包的容量是相同的,都是 V。可以装进背包里的一共有 N 种物品,每种物品都有给定的体积和价值。

在 DD 看来,合理的背包安排方案是这样的:

1. 每个人背包里装的物品的总体积恰等于包的容量。
  2. 每个包里的每种物品最多只有一件,但两个不同的包中可以存在相同的物品。
  3. 任意两个人,他们包里的物品清单不能完全相同。

在满足以上要求的前提下,所有包里的所有物品的总价值最大是多少呢?

     
     
  输入格式 Input Format  
  第一行有三个整数:K、V、N。

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

     
     
  输出格式 Output Format  
  只需输出一个整数,即在满足以上要求的前提下所有物品的总价值的最大值。
     
     
  样例输入 Sample Input  
   
     
     
  样例输出 Sample Output  
   
     
     
  时间限制 Time Limitation  
  1s
     
     
  注释 Hint  
  数据范围

总人数 K<=50。

每个背包的容量 V<=5000。

物品种类数 N<=200。

其它正整数都不超过 5000。

输入数据保证存在满足要求的方案。

     
     
  来源 Source  
  dd 2007 dp 模拟赛

慢慢啃

f[j][u]表示空间为j时的第u优解;

性质:加了一个u循环操作的01背包,i表示加入第i个物品则循环顺序从外到里为i->j->u(就是把原本f[j]=max(f[j-w[i]]+v[i],f[j])的位置变成u的循环操作而已);

初始化:

f[j][u]=负无穷(u循环操作前要判定f[j-w[i]][1]>=0),f[0][1]=0;

u的循环操作:

1.已知f[j]=max(f[j-w[i]]+v[i],f[j]),即f[j]有两种取值方案;

用两个数组st1[u]和st2[u]分别储存f[j-w[i]][u]+v[i]和f[j][u];

2.因为f[j][u]一定优于f[j][u+1],所以st1[u]一定优于st1[u+1],st2[u]同理,所以只需要比较st1和st2中的元素就可以得到当前可以取到的最优值;

所以f[i][u]等于st1[tail1]和st2[tail2]中较大的;

3.因为不能有一样的方案,所以st1[tail1],st2[tail2]中较大的数被f[i][u]取值后,对应的tail++(tail在u循环开始前定义为0或者1);

随着j的增大,方案数是树状增多的,但是前u个最优方案一定是在这棵树的某一个分支上,这个分支的父节点一定是某一个阶段的最优方案,就像分封制一样,离最后的最优方案血缘关系越远优秀程度越差,嗯我是这么理解的.....

因为动态规划每一个阶段的方案只和前一个阶段有关,所以可以在输入数据后直接j循环,不需要v[i]w[i]之类存储每一个状态的数组...

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 int k,v,n;
 8 long long f[5010][51]={};
 9 long long st1[5010]={};
10 long long st2[5010]={};
11 int main(){
12     cin>>k>>v>>n;
13     for(int i=0;i<v;i++){
14         for(int j=0;j<=k;j++){
15             f[i][j]=-99999999;
16         }
17     }
18     f[0][1]=0;
19     for(int i=1;i<=n;i++){
20         int a,b;
21         cin>>a>>b;
22         for(int j=v;j>=a;j--){
23             if(f[j-a][1]>=0){
24                 int p1=1,p2=1;
25                 for(int u=1;u<=k;u++){
26                     st1[u]=f[j-a][u]+b;
27                     st2[u]=f[j][u];
28                     if(st2[p2]>=st1[p1]) f[j][u]=st2[p2++];
29                     else f[j][u]=st1[p1++];
30                 }
31             }
32         }
33     }
34     long long ans=0;
35     for(int i=1;i<=k;i++){
36         ans+=f[v][i];
37     }
38     cout<<ans<<endl;
39     return 0;
40 }

时间: 2024-10-21 05:16:54

背包的第k优解[动态规划]的相关文章

2639-Bone Collector II (01背包之第k优解)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2639 求第k优解的关键代码: 用两个数组记录两种状态(选择或不选择),并且只要记录前k次.在这两个数组中都是前k次可能的最优解.所以我们只要把这两个数组做比较,一直排到k就行了 题目代码: 1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 int dp

hdu2639(背包求第k优解)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2639 题意:给出一行价值,一行体积,让你在v体积的范围内找出第k大的值 分析:dp[i][j][k]表示前i个物品容积为j时的第k优解.那么对于每种状态dp[i][j]都需要维护好前k优解. 每次根据前k优解进行每种取或不取第i件物品,用数组a记录取第i件物品,数组b记录不取,这样 数组a,b了所有能组成j的x种解,最后在x里取前k优解记录下来就好.剩下的肯定不是前k优解了... #include

[JZOJ P1281] [DP]背包的第k优解

@kaike 传送门 看了半天,不会写 没见过这种题型,看了背包九讲,然而只有很简单的几句话 我认为就是多加了一维,变成三维数组 由于必须恰好等于包的容量,所以要赋最小值 然而不能那样递推为什么我也不知道 还没悟出来 嗯加油 1 #include<iostream> 2 using namespace std; 3 long f[51][50001]; 4 int q1[51]; 5 int q2[51]; 6 int main() 7 { 8 int k,v,n; 9 int value,w

01背包之求第K优解——Bone Collector II

http://acm.hdu.edu.cn/showproblem.php?pid=2639 题目大意是,往背包里赛骨头,求第K优解,在普通01背包的基础上,增加一维空间,那么F[i,v,k]可以理解为前i个物品,放入容量v的背包时,第K优解的值.时间复杂度为O(NVK). Talk is cheap. 看代码吧. import java.util.Scanner; public class BoneCollector { public static void main(String[] sur

HDU 2639 (01背包第k优解)

/* 01背包第k优解问题 f[i][j][k] 前i个物品体积为j的第k优解 对于每次的ij状态 记下之前的两种状态 i-1 j-w[i] (选i) i-1 j (不选i) 分别k个 然后归并排序并且去重生成ij状态的前k优解 */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 1010 using namespace std; int T,n,m,k,c[maxn],v[maxn

01背包 HDU 2639,第K优解

只要每次都保存前k优解就可以了 注意当价值一样时,只算一种,所以要进行去重复 的操作 用到了unique, 1 2 2 4 0 0 unique之后1 2 4 0 0 2 Bone Collector II Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2433    Accepted Submission(s): 1277 Prob

DP2_第K优解

转载:http://m.blog.csdn.net/blog/a511310132/13465985 对于求次优解.第K优解类的问题,如果相应的最优解问题能写出状态转移方程.用动态规划解决,那么求次优解往往可以相同的复杂度解决,第K优解则比求最优解的复杂度上多一个系数K.其基本思想是将每个状态都表示成有序队列,将状态转移方程中的max/min转化成有序队列的合并.这里仍然以01背包为例讲解一下.首先看01背包求最优解的状态转移方程:f[i][v]=max{f[i-1][v],f[i-1][v-c

第k优解 hdu 2639

#include<iostream> #include<cstdio> #include<cstring> #define maxn 110 using namespace std; int w[110],v[110],f[1010][110],a[110],b[110]; //f[j][k]表示重量为j时的第k优解 int main() { int t; scanf("%d",&t); while(t--) { int n,m,i,j,k,

HDU 2639 Bone Collector II (DP 第k优解)

题意:输入t,t组测试样例,每组样例输入 n, v, k. 接着输入n个物品的价值,再输入n个物品的体积.求k优解. 分析:dp[n][v][k]表示n个物品,在体积不超过v的情况,第k大的值是多少.dp[i][v][k]与dp[i-1][v][k]与dp[i-1][v-volume[i]]+value[i]有关. #include <iostream> #include <cstdio> #include <cstring> #include <algorith