Vijos P1412 多人背包

P1412多人背包
标签: [显示标签]

描述

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

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

每个人背包里装的物品的总体积恰等于包的容量。 
每个包里的每种物品最多只有一件,但两个不同的包中可以存在相同的物品。 
任意两个人,他们包里的物品清单不能完全相同。 
在满足以上要求的前提下,所有包里的所有物品的总价值最大是多少呢?

格式

输入格式

第一行有三个整数:K、V、N( 1 <= K <= 50, 0 <= V <= 5000,1 <= N <= 200 )。

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

输出格式

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

样例1

样例输入1[复制]

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

样例输出1[复制]

57

限制

各个测试点1s

来源

感谢dd_engi


 
     
 
     
多人背包
 
     
 
     
也就是求背包的第k优解
 
     
 
     
如果是求最优解dp[i][j],那么只需要求max(dp[i - 1][j],dp[i - 1][j - w[i]] + p[i])
 
     
 
     
那么求k优解dp[i][j][1~k],那么只需要求dp[i - 1][j]的前k优解(有序)和dp[i - 1][j - w[i]] + p[i] 的前k优解(有序)
 
     
 
     
那么两个数组归并到dp[i][j][1~k]中,取前k优解即可。
 
     
 
     
那么dp[i]只与dp[i - 1]有关,所以可以少开一维空间
 
     
 
     
膜拜大牛博客
 
     
 
    
代码:
/**多人背包
link=
       
       **/
#include 
       
       
        
        
#include 
        
        
#include 
         
         
          
          
#include 
          
          
           
           
#include 
           
           
             #include 
            
              #include 
             
               #include 
              
                #include 
               
                 #include 
                
                  #include 
                 
                   #include 
                  
                    #include 
                   
                     #include 
                    
                      #include 
                     
                       #include 
                      
                        #include 
                       
                         #include 
                        
                          #define maxn (4000 + 20) #define inf 0x3f3f3f3f #define pi acos(-1.0) using namespace std; typedef long long int LLI; int list1[maxn]; int list2[maxn]; int dp[5500][55]; int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); int n,m,k; scanf("%d%d%d",&k,&m,&n); for(int i = 0; i <= m; i ++) for(int j = 0; j <= k; j ++) dp[i][j] = -99999999; dp[0][1] = 0; for(int i = 1; i <= n; i ++) { int x,y; scanf("%d%d",&x,&y); for(int j = m; j >= x; j --) { int p = 1,q = 1,o = 1; for(int l = 1; l <= k; l ++) { list1[l] = dp[j][l]; list2[l] = dp[j - x][l] + y; } while(o <= k) { if(list1[p] > list2[q] && p <= k) dp[j][o ++] = list1[p ++]; else if(list1[p] <= list2[q] && q <= k) dp[j][o ++] = list2[q ++]; } } } int ans = 0; for(int i = 1; i <= k; i ++) { ans += dp[m][i]; } printf("%d\n",ans); return 0; } 
                         
                        
                       
                      
                     
                    
                   
                  
                 
                
               
              
             
           
          
          
         
         
       
       

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值