博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
01背包入门
阅读量:3897 次
发布时间:2019-05-23

本文共 1884 字,大约阅读时间需要 6 分钟。

此条博客内容部分参考自

题目:有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

基本思路:01背包问题的特点就是,每种物品仅有一件,可以选择放或者不放。

用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}。

基本上所有和背包相关的问题的方程都由它衍生出来。这个状态转移方程的具体含义大概就是:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品放或不放,那么就可以转化为一个只牵扯第i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”;如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。

其中有一维和二维的代码解析:

首先是二维的:代码内有注释解释:

#include
#include
//#include
#include
using namespace std;const int MAX=1010;int N,V;int f[MAX][MAX];int c[MAX],w[MAX]; //费用和价值int main(){
//首先输入对应的费用和价值 scanf("%d%d",&N,&V); for(int i=1;i<=N;i++) scanf("%d%d",&c[i],&w[i]); //第一个i指的是,第i件 for(int i=1;i<=N;i++) for(int v=0;v<=V;v++)//结合上一个循环,也就是把所有情况 :第0件到第n件的容量为0到V的所有价值都选了进来。 {
f[i][v]=f[i-1][v];//在没有选择取不取第i件的前提时,现在的价格是前i-1件 if(v>=c[i])//意思就是假设第i件可取 f[i][v]=max(f[i-1][v],f[i-1][v-c[i]]+w[i]);//那么就判断 } //刚开始不理解,为什么要进行这个循环,直接输出F[N][i]不行吗,代码测试之后发现,确实也可以 //int res=0; //for(int i=0;i<=V;i++)//f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值 //res=max(res,f[N][i]); printf("%d",f[N][V]);}

然后是一维的代码:

下面我们对空间复杂度进行优化,从上面的代码可以看到i从1到N,每次算出了二维数组f[i][0…V]的所有值。那么如果用一个数组f[0…V],可否保证第i次循环结束后f[v]中表示的状态就是我们定义的f[i][v]呢?我们知道,我们的f[i][v]是由f[i-1][v]和f[i-1][v-c[i]]的两个子问题递推而来的,事实上要求,在每次主循环中我们要求如下伪代码的顺序才能保证f[i][v]是由f[i-1][v]和f[i-1][v-c[i]]两个子问题推来的。

也就是所谓的滚动数组

其实就是在于二维数组中:f[i][v]=f[i-1][v] 这一部分,所以对于i来说,每一次都是前一次的叠加,其实本事是没有变的,(能理解最好,不能理解就时常看看)
并且是需要逆序的,二维数组是逆序正序都可以的

#include
#include
#include
using namespace std;const int MAX=1010;int N,V;int f[MAX];int c[MAX],w[MAX]; //费用和价值int main(){
scanf("%d%d",&N,&V); for(int i=1;i<=N;i++) scanf("%d%d",&c[i],&w[i]); for(int i=1;i<=N;i++) for(int v=V;v>=c[i];v--) f[v]=max(f[v],f[v-c[i]]+w[i]);//若v

转载地址:http://lkfen.baihongyu.com/

你可能感兴趣的文章
VC的字符串转换atlconv的使用
查看>>
Twitter的分布式自增ID算法snowflake (Java版)
查看>>
阻抗测量基础
查看>>
天线设计相关性能参数
查看>>
Linux Centos7 rabbitmq安装及集群配置
查看>>
CentOS7 安装配置FastDFS
查看>>
git 拉取gitlab 代码
查看>>
递归算法的时间复杂度
查看>>
数据结构之图(存储结构、遍历)
查看>>
使用sizeof计算类的大小
查看>>
乐观锁与悲观锁——解决并发问题
查看>>
operator 类型转换及重载
查看>>
HTTP状态码
查看>>
TCP/IP详解--举例明白发送/接收缓冲区、滑动窗口协议之间的关系
查看>>
TCP/IP详解--再次深入理解TCP网络编程中的send和recv
查看>>
TCP与UDP收发的时候TCP有缓冲区还是UDP有缓冲区,使用它们时该注意什么?
查看>>
C++中map、hash_map、unordered_map、unordered_set通俗辨析
查看>>
clone的fork与pthread_create创建线程有何不同&pthread多线程编程的学习小结
查看>>
运算符重载参数的顺序对运算是否有影响
查看>>
什么时候要用虚析构函数?
查看>>