简单的背包问题

背包问题动态规划中非常经典的一个问题,本文只包含01背包,完全背包和多重背包。更加详尽的背包问题的讲解请参考崔添翼大神的《背包九讲》

简单的01背包

  • 问题导入:新年到了,mjl马上就要外出旅游。mjl拥有一个容量为P的小背包,他希望在自己的n件体积为Vi的物品中带走的物品体积之和尽可能的多,他最多能带走多少物品?(每件物品只有一个)
  • 问题分析:可以创建一个二维数组dp[i][j],使用0和1表示对于前i件物品是否能凑出j的体积。要判断dp[i][j]的值是否为true,可以查看dp[i-1][j-V[i]]即前i-1件物品是否能凑出j-V[i]的重量出来或者dp[i-1][j]即前i-1件物品已经可以把体积j凑出来。
  • 代码实现:
    memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1; i<=n; i++)
{
for(int j=p; j>=v[i]; j--)
{
if(dp[i-1][j-v[i]] || dp[i-1][j])
{
dp[i][j] = 1;
}
}
}
int ans;
for(int i=p; i>=0; i--)
{
if(dp[n][j])
{
ans = j;
break;
}
}

注意代码中从后向前更新dp[i][j],是为了防止一件物品被使用多次

对于简单01背包问题的优化

显然,在简单01背包问题中,空间复杂度达到了O(n*p)之多。而在每一次更新第i行的数据时,只需要i-1行的数据即可,再向上的数据完全可以舍弃,所以只需要开一个两行的二维数组即可。

01滚动:

  • 只存在第0行和第一行,每次更新数据后将第1行的数据复制到第0行
  • 代码实现:
    memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1; i<=n; i++)
{
for(int j=p; j>=v[i]; j--)
{
if(dp[0][j-v[i]] || dp[0][j])
{
dp[1][j] = 1;
}
}
for(int i=0; i<=n; i++)
{
dp[0][i] = dp[1][i];
}
}
int ans;
for(int i=p; i>=0; i--)
{
if(dp[1][j])
{
ans = j;
break;
}
}

尽管01滚动的空间复杂度已经优化了很多,但是每一次结束后的复制操作增加了时间复杂度。同时最终对于结果有用的只是最后一行,因此有一种优化空间的同时不影响时间复杂度的优化方法,即使用一位数组就地滚动

就地滚动:

  • 只使用一个一位数组,每一次在原来数组的基础上更新数据
  • 代码实现:
    memset(dp,0,sizeof(dp));
dp[0] = 1;
for(int i=1; i<=n; i++)
{
for(int j=p; j>=v[i]; j--)
{
if(dp[j-v[i]] == 1)
{
dp[j] = 1;
}
}
}
int ans;
for(int i=p; i>=0; i--)
{
if(dp[i] == 1)
{
ans = i;
break;
}
}

01背包

  • 问题导入:既然外出旅游,当地的纪念品当然是必不可少的,因此mjl来到了景区内的一家纪念品商店。众所周知,景区的商店往往都是黑店,mjl身上的钱并不能买下他喜欢的所有东西,他对于每一件纪念品做了一个评分,评分越高代表他越喜欢这件纪念品,现在mjl想知道他能带走商品的最大评分和是多少,其中价格为p[i],评分为v[i],携带的钱为m。
  • 问题分析:这里只需要使用一个二维数组dp[i][j]表示对于前i个物品,当已花费j金钱时能够带走的最大价值。状态转移方程为dp[i][j] = max( dp[i-1][j] , dp[i-1][j-p[i]] + v[i] )。

    -代码实现(就地滚动):
    memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
{
for(int j=m; j>=p[i]; j--)
{
dp[j] = max(dp[j], dp[j-p[i]]+v[i]);
}
}
int ans = 0;
for(int i=m; i>=0; i--)
{
ans = max(ans, dp[i]);
}
printf("%d\n",ans);

完全背包

  • 完全背包简单的说就是在01背包的基础上,所有的物品都可以重复购买无限次。既然在01背包中为了防止一件物品被多次使用而从后向前遍历,那么在完全背包中只需要改为从前向后遍历即可
  • 代码实现:
    memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
{
for(int j=p[i]; j<=m; j++)
{
dp[j] = max(dp[j], dp[j-p[i]]+v[i]);
}
}
int ans = 0;
for(int i=m; i>=0; i++)
{
ans = max(ans, dp[i]);
}
printf("%d\n",ans);

未完待续……

【动态规划】【C/C++】简单的背包问题的更多相关文章

  1. 详解动态规划(Dynamic Programming)& 背包问题

    详解动态规划(Dynamic Programming)& 背包问题 引入 有序号为1~n这n项工作,每项工作在Si时间开始,在Ti时间结束.对于每项工作都可以选择参加与否.如果选择了参与,那么 ...

  2. CJOJ 2022 【一本通】简单的背包问题(搜索)

    CJOJ 2022 [一本通]简单的背包问题(搜索) Description 设有一个背包可以放入的物品重量为S,现有n件物品,重量分别是w1,w2,w3,-wn. 问能否从这n件物品中选择若干件放入 ...

  3. 简单的背包问题(入门)HDU2602 HDU2546 HDU1864

    动态规划,我一直都不熟悉,因为体量不够,所以今天开始努力地学习学习. 当然背包从01开始,先选择了一个简单的经典的背包HDU2602. Many years ago , in Teddy's home ...

  4. HDU 1561&HDU 3449 一类简单依赖背包问题

    HDU 1561.这道是树形DP了,所谓依赖背包,就是选A前必须选B,这样的问题.1561很明显是这样的题了.把0点当成ROOT就好,然后选子节点前必须先选根,所以初始化数组每一行为该根点的值.由于多 ...

  5. 51nod 1270 数组的最大代价 思路:简单动态规划

    这题是看起来很复杂,但是换个思路就简单了的题目. 首先每个点要么取b[i],要么取1,因为取中间值毫无意义,不能增加最大代价S. 用一个二维数组做动态规划就很简单了. dp[i][0]表示第i个点取1 ...

  6. 动态规划:HDU2159-FATE(二维费用的背包问题)

    FATE Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

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

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

  8. LFYZ-OJ ID: 1028 背包问题

    背包问题 题目描述 简单的背包问题.设有一个背包,可以放入的重量为s.现有n件物品,重量分别为w1,w2-,wn,(1≤i≤n)均为正整数,从n件物品中挑选若干件,使得放入背包的重量之和正好为s.找到 ...

  9. 【模板】各种背包问题&讲解

                                        背包问题集合 一般来说,动态规划(DP)都是初学者最难闯过的一关,而在这里详细解说动态规划的一种经典题型:背包问题. 这里介绍的 ...

随机推荐

  1. PL/SQL不安装Oracle连接,Oracle instantclient安装

    ================================ ©Copyright 蕃薯耀 2020-01-07 https://www.cnblogs.com/fanshuyao/ 第一步: 下 ...

  2. NetCore文件上传校验返回未授权401,文件仍然执行上传操作,要如何解决呢

    这是代码:https://files.cnblogs.com/files/suterfo/NetCoreTestPro.rar 运行步骤: 一.使用Visual Studio2017打开项目,并F5运 ...

  3. Linux下的python3,virtualenv,Mysql、nginx、redis等常用服务安装配置

    Linux下的python3,virtualenv,Mysql.nginx.redis等常用服务安装配置   学了前面的Linux基础,想必童鞋们是不是更感兴趣了?接下来就学习常用服务部署吧! 安装环 ...

  4. ES的性能优化

    ES的性能优化 es在数据量很大的情况下(数十亿级别)如何提高查询效率? 在es里,不要期待着随手调一个参数,就可以万能的应对所有的性能慢的场景.也许有的场景是你换个参数,或者调整一下语法,就可以搞定 ...

  5. 3.3 Zabbix容器安装

    课程资料:https://github.com/findsec-cn/zabbix 1. yum install docker-latest    :安装最新的docker   ,选择 y  ,等待自 ...

  6. Don't assign one object to another one

    correct way, when changing object, firstly you should create this object and then assign its propert ...

  7. Docker入门(windows安装)

    Docker入门(安装)Docker是一种轻量级容器技术,实际中直接运行在当前操作系统(Linux)上,而不是虚拟机中.PaaS提供了存储,数据库,网络,负载均衡,自动扩展等功能,Docker云平台就 ...

  8. TCP与UDP的一些心得

    1:CC攻击是正常的业务逻辑,大并发让你处理不过来,处理XP SP2,以上的系统都封了RAW格式协议封包自定义,除了基于应用层改协议,之外都是模拟或请求来测试传输层2:UDP不会粘包,不会少包,除非缓 ...

  9. thinkphp 5.0 后台数据修改

    html代码 <table class="easyui-datagrid" data-options="singleSelect:true,collapsible: ...

  10. APFS 宗卷 • APFS(加密)磁盘格式怎么去掉?Mac磁盘加密怎么解除?

    相信很多朋友都因为APFS 宗卷 • APFS(加密)磁盘格式而困扰,这种磁盘加密,导致很多破解版软件都不能安装.那么磁盘加密怎么解除?小编翻阅了一些教程,为您带来APFS 宗卷 • APFS(加密) ...