zoukankan      html  css  js  c++  java
  • 完全背包与01背包的粗浅理解

    一直不是很懂动规,也没有下功夫去恶补,结果前几天比赛被一道完全背包的签到题给恶心到了。
    又找题理解了下,这里记下笔记,有不对的地方欢迎狂喷。(开玩笑的开玩笑的,手下留情。)

    首先看道完全背包入门题:

    题目描述
    设有n种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为M,今从n种物品中选取若干件(同一种物品可以多次选取),使其重量的和小于等于M,而价值的和为最大。

    输入
    第一行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30);

    第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。

    输出
    仅一行,一个数,表示最大总价值。

    样例输入
    10 4
    2 1
    3 3
    4 5
    7 9
    样例输出
    12

    代码:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    
    using namespace std;
    
    struct thing{
        int Price;
        int Weight;
    }board[35];
    
    int M,N;
    
    int f[300];
    
    int main(){
        cin>>M>>N;
        for(int i=0 ; i<N ; i++){
            cin>>board[i].Weight>>board[i].Price;
        }
        for(int i=0 ; i<N ; i++){
            for(int j=board[i].Weight ; j<=M ; j++){
                f[j] = max(f[j],f[j-board[i].Weight]+board[i].Price);   
            }
        }
        printf("max=%d
    ",f[M]);
        for(int i=0 ; i<=M ; i++)printf("%d ",f[i]);
    
    
        return 0;
    }

    关键部分:

    for(int i=0 ; i<N ; i++){
            for(int j=board[i].Weight ; j<=M ; j++){
                f[j] = max(f[j],f[j-board[i].Weight]+board[i].Price);   
            }
        }

    这里我们可以这样理解,首先题目是问我们当背包容量为M时我们最大能装价值总和为多少的东西
    那么我们先不管这个,我们来想一下当背包容量为1时我们最大能装价值总和为多少的东西,根据样例的
    数据显然是0。往下走当背包容量为2时我们最大能装价值总和显然为1,以此类推,那么关键是我们怎样的到这个“1”的。这时候我们就要根据给的物品来看了,如果物品的重量大于包的容量那么明显是放不下,
    而如果包的容量〉=物品那么包就可以选择放这个东西或不放。如果不放那么包里的物品总价值当然会保持不变,即

    f[j]

    而如果选择放,那么就必须拿出与物品重量等值的容量(懂就行了,别在意为啥加质量影响体积),
    那么原先容量为M1的包就可以看成容量为M1-物品重量的包+物品。那么容量为M1的包的价值总和自然等于物品的价值+容量为M1-物品重量的包中物品的价值总和,即

    f[j-board[i].Weight]+board[i].Price

    那么到底放不放呢?当然是取决于放进去总价值是否增大啊,即

    max(f[j],f[j-board[i].Weight]+board[i].Price)

    那么想得到结果只需要用每个物品尝试每个可以装的下物品的包(即〉=Weight )即可。即

    for(int i=0 ; i<N ; i++){
            for(int j=board[i].Weight ; j<=M ; j++){
                f[j] = max(f[j],f[j-board[i].Weight]+board[i].Price);   
            }
        }

    到这里根据前面的理解,我们很容易发现每一个大包的最大物品价值合都跟前面的小包有关。
    我们会先得到小包的值,再用小包的值去影响大包的值,这就是动规的典型思想。

    接下来是01背包
    01背包与完全背包的典型区别在于物品为1个。
    来看道01背包的入门题http://blog.csdn.net/vocaloid01/article/details/77206475

    关键部分:

    for(int i=0 ; i<N ; i++)  
            {  
                for(int j=V ; j>=vol[i] ; j--)  
                {  
                    dp[j] = max(dp[j],dp[j-vol[i]]+val[i]);  
                }  
            }  

    大家可以轻易发现与前面完全背包的区别
    完全背包是从可以装下物品的最小包开始循环到最大包,而01背包正相反。
    而这就是关键点
    举例来说明:
    完全背包中假如最大包为10,现在拿来第一个物品重2值1来进行循环
    则结果0-10各包的值为 0 0 1 1 2 2 3 3 4 4 5。
    而01背包为 0 0 1 1 1 1 1 1 1 1 1。
    易发现完全背包从小往大的过程中无形中同一样物品就会放入很多次而01背包不会。

  • 相关阅读:
    .JS replace方法替换所有字符
    .net framework 4.0,结果还是失败,出现HRESULT 0xc8000222错误代码
    用PowerDesigner15自动将数据库里的表生成ER图
    C#对JSON数据格式的处理
    Type of conditional expression cannot be determined because there is no implicit conversion between 'Common.EnumType.EnumGender' and '<null>'
    如何在string.Format方法中输出大括号({})
    网架构学习笔记
    c#实现javascript中函数escape解码
    Solon 开发,八、注入依赖与初始化
    Solon 开发,七、自定义注解开发汇总
  • 原文地址:https://www.cnblogs.com/vocaloid01/p/9514197.html
Copyright © 2011-2022 走看看