dp一直是短板,现在从最基础的地方开始补

给定背包总容量 M ,n个商品选择,分别有价值vi,占量wi,从中取商品放入背包,令。容量和W=Σwi不超过M,令背包中的价值和V=Σvi最大

然后取法有很多种,分别是

  1. 只取一次
  2. 各种变形,比如:可重复取,只能取有限次。

参考博文:链接

对于最基本的情况1   贴一个vjudge的题目链接

如果暴力做的话就是求全组合,然鹅数据量实在不够,如果穷举就给一直TE了

这个问题最讨厌的地方在于,不能直接使用贪心排序,无论是重量贪心还是v/w贪心都不行,

具体可以参考这篇博文,对各种贪心方式和最优解直接的差距做了一个趋近误差分析,https://blog.csdn.net/weixin_33825683/article/details/94745157

不过,前面的选择会影响后面的,每个物体的优先权会被整体的情况影响,这是不是很耳熟?

01背包的—只取一次—的情况,与最短路很相似,

  • 01背包前面的商品会影响后面的,最短路前面选择的节点会影响后面的节点,
  • 01背包要求价值最大,最短路要求路径长度最小
  • 01背包每次决策是否放入某物品,最短路每次决策是否放入某个节点

可以把物品看成节点

一点区别,

  • 01背包限制物品总重量不能超过M,不要求两物品之间要有什么联系
  • 最短路选边的限制是两节点间是否存在边,不要求节点选择有限,比如只能选几个节点之类的

回忆解决最短路的算法,可以说,Floyd和Dijikstra,其实就是动态规划解决最短路问题

  • Floyd是把每一个点到其它点的最短路径记录下来,从子问题,逐层扩展,不断更新邻接表的值
  • Dijikstra是确定起点,把该起点到其他位置的最短路都找到,然后从子问题,逐层扩展,不断更新邻接表的值

Floyd的子问题更新方式:dp【i】【j】=min(dp【i】【k】+dp【k】【j】,dp【i】【j】),外面是三重循环,O(n2)

  • dp【i】【j】表示已有的不放入k节点的   i - j   最短路径,
  • k 表示是否在   i - j 之间放入k节点,放进去时,新路径 R=dp【i】【k】+dp【k】【j】

Dijikstra的子问题更新方式 ,dp【i】=min(dp【j】+ r【j】【i】,dp【i】)

  • dp【i】表示从起点到 i 最短路径 ,r【j】【i】表示已知 j - r 的直接路径,
  • 确定起点,不需更新完所有的最短路,而是,只更新分支树

可以发现,01背包和Floyd非常像,因为它需要把整张路径邻接表都初始化

仿照以上思路,把物品看成节点,要求V最大,V/M最大,即总容量的利用率最高,即M分配给不同的 wi,要求每一份子空间的,V最大

    01背包每次决策是否放入某物品,最短路每次决策是否放入某个节点

可以这样写:dp【j】=max(dp【j】,dp【j-w【i】】+ v【i】),j  》= w【i】 ; j = m 从大到小,或者,m=0从小到大遍历完,决策时 i 为常数, 所以 i 在最外层

  • dp【j】表示 空间 j  时 最大价值(不需要装满,只要能放进去就检查一次),同理dp【j-w【i】】表示不放入 dp【i】
  • i 表示第 i 件物品是否放进去容量上限为   j  的背包,每件物品从1到m都测一次;
  • 放进去时,新价值 V=dp【j-w【i】】+v【i】,dp【m】为最终结果

也可以这样写,比较常见的二维数组写法:dp【i】【j】=max(dp【i】【j-1】,dp【i-w【j】】【j-1】+ v【j】)j《  n,j  和 上面的 i 是一个道理

  • dp【i】【j】表示空间为 i  时,放入第 j 件物品 , 得到的最大价值(不需要装满)的效果
  • j   表示 第 j 件 物品是否放进去背包   ,第 j  件恰好也是 第 j 号  ,放进去时,新价值 V=dp【i-w【j】】【j-1】+ v【j】,
  • 这个好处是可以比较方便地记录下放入的背包编号,只需要另设一个数组 ,令 r【j】= k ,不断更新即可

注意枚举的顺序是正序还是逆序, https://blog.csdn.net/yandaoqiusheng/article/details/84929357

  • j = m 从大到小,到 wi
  • j = 0 从小到大,到 m

AC代码,写法1,实际实现的时候,需要把dp【j】从 j=m 到 j=0,j-- 一直试下去;j = m 从大到小(m,m-1,m-2,,,m-x=wi)比从小到大排好,从小到大还要循环内再判断

 #include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int M=1e5+;
int w[M],v[M];
int n,m;
int dp[M]; int T;
void f() {
memset(dp,,sizeof(dp));
//dp[j]=max(dp[j],dp[j-w[i]]+v[i]);i(1,n),j>=w[i],
//容量初始值j=m
//决策时i为常数, 所以 i 在最外层
for(int i=; i<=n; i++) {
for(int j=m; j>=w[i]; j--) { //能取等!!!
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
}
cout<<dp[m]<<endl;
}
/*
5 1000
144 990
487 436
210 673
567 58
1056 897 2099
*/
int main() { cin>>n>>m;
for(int i=; i<=n; i++)cin>>w[i]>>v[i];
f(); return ;
}

不能AC的写法2,数据量太大 ,二维会爆炸

 #include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int M=1e5+;
int w[M],v[M];
int n,m;
int dp[M][]; void f() {
memset(dp,,sizeof(dp));
//dp[i][j]=max(dp[i][j-1],dp[i-w[k]][j-1]+v[k]);i(1,n),i>w[k],
//容量初始值i=m
//决策时i为常数, 所以 i 在最外层
int ans=;
for(int j=; j<=n; j++) {
for(int i=; i<=m; i++) {
if(i>w[i])dp[i][j]=max(dp[i][j-],dp[i-w[j]][j-]+v[j]);
else dp[i][j]=dp[i][j-]; } } cout<<dp[m][n]<<endl;
} /*
5 1000
144 990
487 436
210 673
567 58
1065 897 2099
*/
int main() { cin>>n>>m;
for(int i=; i<=n; i++)cin>>w[i]>>v[i];
f();
return ;
}

这种情况不能按照    i = m 从大到小(m,m-1,m-2,,,m-x=wi)否则,更新是不完全,需要将dp【m】【1-n】都检查一次,不能直接通过输出dp【m】【n】来决定,

原因在于,此时dp【i】【j】从 j=1 到 j=n有多个值,个别n可能并没有数值,而写法1直接就是这些情况中的最大值,所以不用再找

动态规划_01背包_从Dijikstra和Floyd入手,彻底理解01背包的更多相关文章

  1. 动态规划——背包问题python实现(01背包、完全背包、多重背包)

    目录 01背包问题 完全背包问题 多重背包问题 参考: 背包九讲--哔哩哔哩 背包九讲 01背包问题 01背包问题 描述: 有N件物品和一个容量为V的背包. 第i件物品的体积是vi,价值是wi. 求解 ...

  2. 背包问题(01背包,完全背包,多重背包(朴素算法&&二进制优化))

    写在前面:我是一只蒟蒻~~~ 今天我们要讲讲动态规划中~~最最最最最~~~~简单~~的背包问题 1. 首先,我们先介绍一下  01背包 大家先看一下这道01背包的问题  题目  有m件物品和一个容量为 ...

  3. ZOJ 3956 Course Selection System [01背包]

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3956 题意:就是给你Hi,Ci的值,问怎么取使得下面那个式子的值最大: 理 ...

  4. DP:Cow Exhibition(POJ 2184)(二维问题转01背包)

        牛的展览会 题目大意:Bessie要选一些牛参加展览,这些牛有两个属性,funness和smartness,现在要你求出怎么选,可以使所有牛的smartness和funness的最大,并且这两 ...

  5. bzoj4457: 游戏任务--双层01背包

    这题和NOIP的金明的预算方案(?)很像,只不过附件的数量增多了 如果对主件进行一次01背包,再套一层附件的01背包O(n4)肯定会爆.. 所以我们可以先预处理出,对于每个主件,花的时间为k的情况下, ...

  6. HDu 3449 (有依赖的01背包) Consumer

    题意: 有n件物品,对应有不同的价格和价值,这是典型的01背包.但现在有了一个限制,要买物品先买能装这件物品的特定的盒子,盒子的价值为0 代码理解得还不是太好,感觉这是一个“二重”的01背包.首先假设 ...

  7. hdu 3449 (有依赖的01背包)

    依赖背包 事实上,这是一种树形DP,其特点是每个父节点都需要对它的各个儿子的属性进行一次DP以求得自己的相关属性. fj打算去买一些东西,在那之前,他需要一些盒子去装他打算要买的不同的物品.每一个盒子 ...

  8. 01背包java实现(入门到精通)

    一.什么是01背包 01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2至Wn,与之相对应的价值为P1,P2至Pn.01背包是背包问题中最简单的问题.01背包的约束条件是给定 ...

  9. HDU2191--多重背包(二进制分解+01背包)

    悼念512汶川大地震遇难同胞--珍惜现在,感恩生活 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Jav ...

随机推荐

  1. angular自启动过程

    angularJS的源代码整体上来说是一个自执行函数,在angularJS加载完成后,就会自动执行了. 即,在window上暴露一个唯一的全局对象angular, 如果window.angular已经 ...

  2. Red Team 工具集之网络钓鱼和水坑攻击

    来自:信安之路(微信号:xazlsec),作者:myh0st 参考项目:https://github.com/infosecn1nja/Red-Teaming-Toolkit 上图是一个 Red Te ...

  3. Linux 基础篇(二)

    1.linux 关机和重启 关机: shutdown  -h  10:20  # 指定时间关机 shutdown -h now    # 马上关机 shutdown -h +10  # 10分钟后关机 ...

  4. NASNet : Google Brain经典作,改造搜索空间,性能全面超越人工网络,继续领跑NAS领域 | CVPR 2018

    论文将搜索空间从整体网络转化为卷积单元(cell),再按照设定堆叠成新的网络家族NASNet.不仅降低了搜索的复杂度,从原来的28天缩小到4天,而且搜索出来的结构具有扩展性,在小模型和大模型场景下都能 ...

  5. Oracle时间日期计算--计算某一日期为一年中的第几周

    Oracle时间日期计算--计算某一日期为一年中的第几周 select to_char(sysdate-10,'yyyymmdd')||':iw:'||to_char(sysdate-10,'iw') ...

  6. Flume数据采集结合etcd作为配置中心在爬虫数据采集处理中的架构实践。

    Apache Flume是一个分布式的.可靠的.可用的系统,用于有效地收集. 聚合和将大量日志数据从许多不同的源移动到一个集中的数据存储,但是其本身是以本地properties作为配置的,配置无法做到 ...

  7. 分布式配置中心Apollo

    1,什么是分布式配置中心 项目中配置文件比较繁杂,而且不同环境的不同配置修改相对频繁,每次发布都需要对应修改配置,如果配置出现错误,需要重新打包发布,时间成本较高,因此需要做统一的分布式注册中心,能做 ...

  8. mavlink协议移植问题

    mavlink协议移植问题 mavlink源代码是一个代码库,使用的时候只需要将mavlink.h头文件包含到工程项目中即可. mavlink通信协议是无状态的连接,一般采用心跳消息跟踪系统是否存在. ...

  9. Selenium Grid 的使用

    简介 Selenium Grid 是 selenium 的三大组件之一,允许用户同时在不同的机器和系统上测试不同的浏览器,可以分布式的来执行我们的自动化测试,也可以测试不同浏览器的兼容性. Selen ...

  10. 【nodejs 爬虫】使用 puppeteer 爬取链家房价信息

    使用 puppeteer 爬取链家房价信息 目录 使用 puppeteer 爬取链家房价信息 页面结构 爬虫库 pupeteer 库 实现 打开待爬页面 遍历区级页面 方法一 方法二 遍历街道页面 遍 ...