[01背包] 背包问题求具体方案(01背包+求方案数+思维)
文章目录
- 0. 前言
- 1. 01背包+求方案数+思维
0. 前言
相关:
- [背包] 背包问题算法模板(模板)
1. 01背包+求方案数+思维
12. 背包问题求具体方案
求方案数也是背包问题、dp
的一大考点。本题仅以 01 背包为例。其实所有的 dp
问题都可以求出来状态转移的具体方案。所有的状态构成图,针对于 min
转移的话,其实就是求最短路路径,针对 max
转移的话,其实就是求最长路路径。
状态转移方程为 f[i][j] = max(f[i-1][j], f[i-1][j-vi]+wi)
,其实就是决策出每个 i
的状态转移到底是从第一项还是第二项转移过去的。那么当我们求完之后倒着推一遍就能得到转移过来的最短路径了。 例如,答案 f[n]m]
转移情况有三种:
- 当
f[n][m]=f[n-1][m]
的时候,不选第n
个物品,可以得到最大价值 - 当
f[n][m]=f[i-1][j-vi]+wi
,选择第n
个物品,可以得到最大价值 - 当
f[n][m]=f[i-1][j-vi]+wi
或者f[n][m]=f[n-1][m]
,第n
个物品选不选都可以得到最大价值
注意:
- 需要使用两维状态,需要
i
这个序号,最后需要输出 - 因为本题需要按字典序输出,那么肯定是从第 1 个物品开始考虑
- 当
f[1][m]=f[2,m-v[1]]+w[1]
选第一个能得到最优解 - 当
f[1][m]=f[2,m]
,不选第一个能得到最优解 - 当
f[1][m]=f[2,m-v[1]]+w[1]=f[2,m]
选不选第一个都能得到最优解。但还是选第一个,因为它字典序最小
- 当
- 但是,得到字典序路径是需要反着倒推的,所以枚举物品的时候就从第
n
个物品枚举到第 1 个物品,这样逆序枚举。求出来的当前背包最大价值应为f[1][m]
,这样是很灵活方便的- 代码一定理解透本质,灵活多变
代码:
#include <iostream>
#include <algorithm>using namespace std;const int N = 1005;int n, m;
int v[N], w[N];
int f[N][N]; int main() {cin >> n >> m;for (int i = 1; i <= n; ++i) cin >> v[i] >> w[i];for (int i = n; i >= 1; --i) for (int j = 0; j <= m; ++j) {f[i][j] = f[i + 1][j];if (j >= v[i]) f[i][j] = max(f[i][j], f[i + 1][j - v[i]] + w[i]);}// 在此,f[1][m]就是最大数量int j = m;for (int i = 1; i <= n; ++i) if (j >= v[i] && f[i][j] == f[i + 1][j - v[i]] + w[i]) {cout << i << ' ';j -= v[i];}return 0;
}
一般的,开辟一个数组专门用以记录状态转移过程也能完成状态记录。这是更为一般的方式。
在此,有递归、非递归两种写法。参考大佬题解:背包问题求具体方案(递归版本)
#include <iostream>
#include <algorithm>using namespace std;const int N = 1005;int n, m;
int v[N], w[N];
int f[N][N], g[N][N];// 递归打印,参考:https://www.acwing.com/solution/content/19760/
void print(int x,int y)
{if(x == n + 1) return;int k = way[x][y];//判断是否选择了第x件物品if(k) cout<<k<<' ';//在递归函数的上面为由根节点到叶子节点进行操作print(x+1,y-v[k]);//在递归函数的下面进行操作,为叶子节点遍历完了,回溯由子节点到根节点进行操作}int main() {cin >> n >> m;for (int i = 1; i <= n; ++i) cin >> v[i] >> w[i];for (int i = n; i >= 1; i --) for (int j = 0; j <= m; j ++) {f[i][j] = f[i + 1][j];if (j >= v[i]) {if (f[i][j] <= f[i + 1][j - v[i]] + w[i]) { f[i][j] = max(f[i + 1][j], f[i + 1][j - v[i]] + w[i]);g[i][j] = i;}}}// 递归// print(1, m);// 非递归int j = m;for (int i = 1; i <= n; ++i) {if (j >= v[i]) {if (g[i][j]) {cout << g[i][j] << ' ';j -= v[i];}}}return 0;
}
[01背包] 背包问题求具体方案(01背包+求方案数+思维)相关推荐
- 二维背包问题(二维0-1背包)
二维0-1背包问题 问题描述 算法思路与代码实现 方法一:普通动归方法 方法二:空间优化法 代码1:方法一 从n个物品中的第1个物品开始考虑(从前往后考虑). 从n个物品中的第n个物品开始考虑(从后往 ...
- 背包问题详解:01背包、完全背包、多重背包
参考链接: http://www.cnblogs.com/fengty90/p/3768845.html http://blog.csdn.net/mu399/article/details/7722 ...
- 背包九讲系列1——01背包、完全背包、多重背包
我在进行一些互联网公司的技术笔试的时候,对于我来说最大的难题莫过于最后的那几道编程题了,这对算法和数据结构有一定程度上的要求,而"动态规划"又是编程题中经常出现的算法类型,并且对于 ...
- 背包算法(一)-01背包-史上最详细解答
背包算法(一)-01背包-史上最详细解答 1. 题目 2. 分析 2.1 状态表示 2.2 状态计算 3. 实现 4. 优化 5. 测试 1. 题目 问题描述:有n件物品和容量为m的背包,给出i件物品 ...
- [01背包] 宠物小精灵之收服(01背包+二维费用背包+思维)
文章目录 0. 前言 1. 01背包裸题 0. 前言 相关: [背包] 背包问题算法模板(模板) 1. 01背包裸题 1022. 宠物小精灵之收服 每个精灵仅被收服一次,故可以考虑 01 背包,是典型 ...
- 01背包与完全背包(动态规划)(01背包)
题目描述 一个旅行者有一个最多能负载m公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分 输入格式 第一行:两个整数,M(背包容量,M<=200)和N(物品数量, ...
- 01背包问题分支限界java_分支限界法-01背包问题
1.分支限界法介绍 分支限界法类似于回溯法,也是在问题的解空间上搜索问题解的算法.一般情况下,分支限界法与回溯法的求解目标不同.回溯法的求解目标是找出解空间中满足约束条件的所有解:而分支限界法的求解目 ...
- c语言 用回溯算法解决01背包问题,回溯法解决01背包问题
<回溯法解决01背包问题>由会员分享,可在线阅读,更多相关<回溯法解决01背包问题(21页珍藏版)>请在人人文库网上搜索. 1.回溯法解决01背包问题,回溯法解决01背包问题, ...
- 01型背包问题解题总结(二维)
前言:01型背包问题(一维)的链接: https://blog.csdn.net/qq_56430444/article/details/118157798 完全背包问题链接: https://blo ...
最新文章
- 操纵神经元构造后门,腾讯朱雀实验室披露AI模型新型攻击手法
- 批处理文件中判断是否64位系统
- 快速上手RaphaelJS--RaphaelJS_Starter翻译(一)
- java异步框架feed,Java:IO流里面的BuffeedReader
- 去掉“3_人民日报语料”中每行前边的数字编号,改成“1, 2,......”
- python中os.system.获取输出信息_python中os.system()的返回值
- 设置linux英文环境,英文Linux里中文和日文用户环境设置
- 捕获Java堆转储的7个选项
- 支付宝生活号,同时出现俩网址,到底哪个真哪个假?
- matlab green函数,地基土的传Green函数编辑中……
- C语言判断素数的几种方法
- django基础知识总结
- 如何制作简单的html静态网页
- Vue----组件注册
- 结合可变形注意力的视觉Transformer
- (二)WebService之调用soap服务
- shell sftp 命令大全
- 高德地图-初始化的时候获取行政区边界和中心点
- NVM - Nodejs的版本管理工具安装和使用
- Android局域网对讲,基于Android系统机器人局域网对讲方法与流程
热门文章
- SecureCRT目录乱码
- 计算机中的表示方法,计算机应用基础第三章计算机中信息的表示方法
- 耍耍VSCode1 - 1分钟变身小霸王
- html的网页怎么打包成网址,如何将网址打包成APP?(详细教程)
- 【Linux】win10/ubuntu 双系统安装遇到 gnu grub 2.0.3 或者 error symbol ‘grub_calloc‘ not found 的解决方法
- 【每日早报】2019/11/05
- 十二 ES json数据格式
- 删除oracle中的一列数据,Oracle删除表数据
- 蓝桥杯2N皇后问题-使用Python实现
- 扫雷游戏的实现步骤和代码