完全背包与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\n",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背包不会。

转载于:https://www.cnblogs.com/vocaloid01/p/9514197.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值