码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2017-11-04 18:14:02      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:不能   add   limit   for   size   open   log   width   输入格式   

 

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 }
View Code

 

 

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

标签:不能   add   limit   for   size   open   log   width   输入格式   

原文地址:http://www.cnblogs.com/137shoebills/p/7783628.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!