• 混合背包(dp)


    有 N 种物品和一个容量是 V 的背包。

    物品一共有三类:

    第一类物品只能用1次(01背包);
    第二类物品可以用无限次(完全背包);
    第三类物品最多只能用 si 次(多重背包);
    每种体积是 vi,价值是 wi。

    求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
    输出最大价值。

    输入格式
    第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。

    接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。

    si=−1 表示第 i 种物品只能用1次;
    si=0 表示第 i 种物品可以用无限次;
    si>0 表示第 i 种物品可以使用 si 次;
    输出格式
    输出一个整数,表示最大价值。

    数据范围
    0<N,V≤1000
    0<vi,wi≤1000
    −1≤si≤1000
    输入样例
    4 5
    1 2 -1
    2 4 1
    3 4 0
    4 5 2
    输出样例:
    8

    思路:就是各种背包组合
    0 1 背包 每一个物品只能装一次 倒序遍历保证每一次物品只选择一次
    完全背包 物品可以无限装 顺序遍历 装满为止 无限装
    多重背包 与完全背包不同在于 每一个物品限定了次数 这里使用了二进制优化方案 把每一个次数 化成二进制来拼凑 最后 像0 1 背包组合起来 凑出容量不超过V的最大值 优化计算量成logn

    
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N = 1010;
    int dp[N],V[N],W[N];
    int n , m;
    
    int main()
    {
        cin  >> n >> m ;
        
        for(int i = 0 ; i < n ; i ++)
        {
            int v ,w ,s;
            cin >> v >> w >> s;
            int cnt = 0 ;
            if(s == -1)
            {
                for(int j = m ; j >= v ; j --)
                {
                    dp[j] = max(dp[j] , dp[j - v] + w);
                }
             continue;
            }
            else{
                
            if(s == 0 )
            {
                for(int j = v; j<= m ; j++ )
                {
                    dp[j]=max(dp[j],dp[j-v]+w);
                }
             continue;
            }
           if(s)//二進制優化一下
           {
               int k =  1; 
               memset(V,0,sizeof V);
               memset(W,0,sizeof W);
               while(k <= s)
               {
                   cnt++;
                   V[cnt] = k * v;
                   W[cnt] = k * w;
                   s-=k;
                   k*=2;
               }
               if(s >0)
               {
                   cnt ++;
                   V[cnt] =s * v;
                   W[cnt] =s * w;
               }
                 int t = cnt;
               for(int i = 1; i <= t ; i ++)
               {
                   for(int j = m ; j >= V[i] ; j --)
                   {
                       dp[j] = max(dp[j],dp[j - V[i]] + W[i]);
                   }
               }
           }
                
            }
         
         
            
        }
        cout << dp[m] << endl;
        
        return 0 ;
    }
    
  • 相关阅读:
    PhoneApplicationPage 之观察 触摸事件 GIS
    读书笔记 之 image GIS
    button 样式 GIS
    TextBlock GIS
    textgame GIS
    c#对List或ListArray或string组数 用linq进行分组统计
    彗星撞地球 怀念下Warez组织的经典力作(15G动画压缩成64Kb的那个)
    .NET Framework各版本独立下载.NET Framework 3.5下载.NET Framework 2.0下载
    asp.net 导出excel 表之后 按钮 页面控件失效不可用,没反应的解决办法。
    SQL Sever 各版本下载 SQL Server 2012下载SQL Server 2008下载SQL Server 2005 下载SQL Server 2000 下载
  • 原文地址:https://www.cnblogs.com/wk-love-zsy/p/13900045.html
Copyright © 2020-2023  润新知