Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >算法基础-动态规划

算法基础-动态规划

作者头像
她的店里只卖樱花
发布于 2022-10-31 08:46:06
发布于 2022-10-31 08:46:06
48000
代码可运行
举报
文章被收录于专栏:常用算法模板常用算法模板
运行总次数:0
代码可运行

背包问题

01.01背包问题

题目描述

N 件物品和一个容量是 V 的背包。每件物品只能使用一次。

i 件物品的体积是 v_i,价值是 w_i

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。

输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。

接下来有 N 行,每行两个整数 v_i,w_i,用空格隔开,分别表示第 i件物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0<N,V\le 10000<v_i,w_i≤1000

输入样例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
4 5
1 2
2 4
3 4
4 5

输出样例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
8

题解

时间复杂度

O(n \cdot m)

核心思想

version1:2维暴力(朴素)做法

f[i][j] —> 在不超过j容积的情况下前选择前i个物品的最优解

version2:1维优化版本

由二维可知我们跟新f[i][j] 只需要用到f[i - 1]状态 也就是前i - 1个物品的状态又因为f[i - 1]已经是最优解 所以我们可以用所谓的的滚动数组进行优化 即: if(j ≥ v)f[j] = max(f[j], f[j - v] + w); 如果从前往后遍历的话我们用f[i - 1] 来跟新 f[i] 的时候就不能保证对于f[i]来说是用同一时期f[i - 1]进行跟新会导致数据错误 总结来说就一句话 如果用到上层状态就逆序遍历 否则就顺序遍历

核心函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// version1

for(int i = 1; i <= n; i ++ ) 
{
	int v, w; cin >> v >> w; 
	for(int j = 0; j <= m; j ++ )
		f[i][j] = f[i - 1][j]; 
		if(j >= v] f[i][j] = max(f[i][j], f[i - 1][j - v] + w);
}
// version2 

for(int i = 1; i <= n; i ++)
{
		int v, w; cin >> v >> w; 
		for(int j = w; j >= v; j -- )
			f[j] = max(f[j], f[j - v] + w); 
}

代码实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>

using namespace std;

const int N = 1010;
int n, m;
int v, w;
int f[N];

int main (){
    cin >> n >> m;
    for(int i = 1; i <= n; i ++)
    {
        cin >> v >> w;
        for(int j = m; j >= v; j --)
            f[j] = max(f[j], f[j - v] + w);
    }
    cout << f[m] << endl;
    return 0;
}

02.完全背包问题

03.多重背包问题

04.多重背包问题II

05分组背包问题

线性DP

01.数字三角形

02.最长上升子序列

03.最长上升子序列II

04.最长公共子序列

05.最短编辑距离

题目描述

给定两个字符串 AB,现在要将 A 经过若干操作变为 B,可进行的操作有:

  1. 删除–将字符串 A 中的某个字符删除。
  2. 插入–在字符串A 的某个位置插入某个字符。
  3. 替换–将字符串A 中的某个字符替换为另一个字符。

现在请你求出,将A 变为B 至少需要进行多少次操作。

输入格式

第一行包含整数 n,表示字符串 A 的长度。

第二行包含一个长度为 n 的字符串 A

第三行包含整数 m,表示字符串 B 的长度。

第四行包含一个长度为 m 的字符串 B

字符串中均只包含大小写字母。

输出格式

输出一个整数,表示最少操作次数。

数据范围

1 \le n, m \le 1000

输入样例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
10 
AGTCTGACGC
11 
AGTAAGTAGGC

输出样例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
4

题解

时间复杂度

O(n^2)

状态表示:f[i][j]

集合:将a[1\sim i]变成b[1 \sim j]的操作方式

属性:min

状态计算

有三种操作,所以有三个子集 ok子集划分完了 考虑状态转移的时候 先考虑如果我没有进行这个操作应该是什么状态 然后考虑你进行这一步操作之后会对你下一个状态造成什么影响 然后再加上之前状态表示中你决策出来的那个DP属性 这样就可以自然而然地搞出来转移方程啦

  • 删除操作: ​

a[i]删掉之后a[1\sim i]b[1\sim j]匹配 ​

所以之前要先做到a[1\sim (i-1)]b[1\sim j]匹配 ​

f[i-1][j] + 1

  • 插入操作:

插入之后a[i]b[j]完全匹配,所以插入的就是b[j]

那填之前a[1\sim i]b[1\sim (j-1)]匹配

f[i][j-1] + 1

  • 替换操作:

a[i]改成b[j]之后想要a[1\sim i]b[1\sim j]匹配

那么修改这一位之前,a[1\sim (i-1)]应该与b[1\sim (j-1)]匹配

f[i-1][j-1] + 1

但是如果本来a[i]与b[j]这一位上就相等,那么不用改,即

f[i-1][j-1] + 0

好的那么f[i][j]就由以上三个可能状态转移过来,取个min

细节:

f[0][j]如果a初始长度就是0,那么只能用插入操作让它变成b

f[i][0]如果同样地,如果b的长度是0,那么a只能用删除操作让它变成b

核心函数(转移方程):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= m; j ++)
        {
            f[i][j] = min(f[i - 1][j], f[i][j - 1]) + 1;
            int flg = a[i] != b[j];
            f[i][j] = min(f[i - 1][j - 1] + flg, f[i][j]);
        }

代码实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <cstring>

using namespace std;
const int N = 1010; 

int f[N][N];
char a[N], b[N];
int n, m;

int main(){
    cin >> n >> a + 1 >> m >> b + 1;
    memset(f, 0x3f, sizeof f);
    for(int i = 0; i <= n; i ++)
        f[i][0] = i;
    for(int i = 0; i <= m; i ++)
        f[0][i] = i;
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= m; j ++)
        {
            f[i][j] = min(f[i - 1][j], f[i][j - 1]) + 1;
            int flg = a[i] != b[j];
            f[i][j] = min(f[i - 1][j - 1] + flg, f[i][j]);
        }
    cout << f[n][m] << endl; 
    return 0;
}

06.编辑距离

题目描述

给定 n 个长度不超过 10 的字符串以及 m 次询问,每次询问给出一个字符串和一个操作次数上限。

对于每次询问,请你求出给定的 n 个字符串中有多少个字符串可以在上限操作次数内经过操作变成询问给出的字符串。

每个对字符串进行的单个字符的插入、删除或替换算作一次操作。

输入格式

第一行包含两个整数 nm

接下来n 行,每行包含一个字符串,表示给定的字符串。

再接下来 m 行,每行包含一个字符串和一个整数,表示一次询问。

字符串中只包含小写字母,且长度均不超过 10

输出格式

输出共 mm 行,每行输出一个整数作为结果,表示一次询问中满足条件的字符串个数。

数据范围

1 \le n, m \le 1000,

输入样例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
3 2
abc
acd
bcd
ab 1
acbd 2

输出样例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1
3

题解

区间DP

01.石子合并

数位DP

01.整数划分

题目描述

一个正整数 n 可以表示成若干个正整数之和,形如:n = n_1 + n_2 + … + n_k,其中 n_1 \ge n_2 \ge … \ge n_k, k \ge 1

我们将这样的一种表示称为正整数 n 的一种划分。

现在给定一个正整数 n,请你求出 n 共有多少种不同的划分方法。

输入格式

共一行,包含一个整数 n

输出格式

共一行,包含一个整数,表示总划分数量。

由于答案可能很大,输出结果请对 10^9 + 7 取模。

数据范围

1 \le n \le 1000

输入样例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
5

输出样例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
7

题解

时间复杂度

O(n^2)

思想和完全背包一致

f[i][j] = f[i - 1][j] + f[i - 1][j - i] + f[i - 1][j - 2i] + f[i - 1][j - 3i]

f[i][j - i] = f[i - 1][j - i] + f[i - 1][j - 2i] + f[i - 1][j - 3i]

f[i][j] = f[i - 1][j] + f[i][j - i]

压缩之后:

f[j] += fj - i

核心函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for(int i = 1; i <= n; i ++)
    for(int j = i; j <= n; j ++)
        f[j] += f[j - i];

代码实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>

using namespace std; 

const int N = 1010, MOD = 1e9 + 7;

int n, f[N];

int main(){
    cin >> n; 
    f[0] = 1;
    for(int i = 1; i <= n; i ++)
        for(int j = i; j <= n; j ++)
            f[j] = (f[j] + f[j - i]) % MOD;
    cout << f[n] << endl; 
    return  0;
}

状态压缩DP

01.蒙德里安的猜想

02.最短Hamilton路径

树形DP

01.没有上司的舞会

记忆化搜索

01.滑雪

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
动态规划专题——背包模型
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。
浪漫主义狗
2022/09/19
1.1K0
掌握套路,你也会用动态规划
动态规划并不是一种具体的算法,而是一种思想,个人觉得就是缓存+枚举,把求解的问题分成许多阶段或者多个子问题,然后按顺序求解各子问题。前一子问题的解为后一子问题提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。
Java识堂
2020/07/13
4740
算法:动态规划
上面是一个按照时间段发生的任务a,b,c,d,e,f,g,h,有的任务之间会有时间重叠。定义:
用户3578099
2022/04/18
1.7K0
算法:动态规划
JS算法之动态规划
今天,我们继续探索JS算法相关的知识点。我们来谈谈关于「动态规划」的相关知识点和具体的算法。
前端柒八九
2022/12/19
6.2K0
JS算法之动态规划
动态规划专题刷题记录③:背包问题
从上图中可以看出,01背包每次计算i时的状态只用到了i-1的状态,所有可以舍去i这一维,优化成一维dp。
Here_SDUT
2022/06/29
1.7K0
动态规划专题刷题记录③:背包问题
经典算法之动态规划
动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。在面试笔试中动态规划也是经常作为考题出现,其中较为简单的DP题目我们应该有百分之百的把握顺利解决才可以。
用户3467126
2019/11/26
5510
【算法】动态规划(二)
上一篇,介绍了动态规划DP的概念,以及暴力递归和动态规划的关系。这一篇,将介绍几道经典的动态规划题
MapleYe
2020/03/28
4250
巧解动态规划问题
前言:最近在力扣刷题,但是之前从没有接触过算法题,有的看答案都看不懂,后来做的题做多了发现有好多类似的题目,所以我打算总结一下规律。
wsuo
2020/07/31
7810
巧解动态规划问题
【算法/训练】:动态规划DP
动态规划(Dynamic Programming,DP)是一种在数学、管理科学、计算机科学、经济学和生物信息学等领域中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题
IsLand1314
2024/10/15
4200
【算法/训练】:动态规划DP
【算法统治世界】动态规划 个人笔记总结
动态规划可以被视为一种有限状态自动机,其中每个状态代表了问题的一个子集,状态之间的转移代表了子问题之间的关联。在有向无环图(Directed Acyclic Graph,简称DAG)中,每个节点代表一个状态,而边则代表了状态之间的转移关系。通过这种方式,动态规划将问题转化为在一个DAG上寻找最优路径的问题。
苏泽
2024/04/10
1150
【算法统治世界】动态规划 个人笔记总结
动态规划与练习题
动态规划(Dynamic Programming)是分治思想的延伸,通俗一点来说就是大事化小,小事化无的艺术。
二肥是只大懒蓝猫
2023/03/30
2990
动态规划与练习题
动态规划设计
输入: [10,9,2,5,3,7,101,18] 输出: 4 解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
Tim在路上
2020/08/04
6210
动态规划 4、基础背包问题总结(从01开始)「建议收藏」
简述:n种物品,每种一个,选或不选随你,背包一定有容量,求不超过容量的情况下,价值最大。
全栈程序员站长
2022/09/06
9870
动态规划 4、基础背包问题总结(从01开始)「建议收藏」
浅谈我对动态规划的一点理解---大家准备好小板凳,我要开始吹牛皮了~~~
前言 作为一个退役狗跟大家扯这些东西,感觉确实有点。。。但是,针对网上没有一篇文章能够很详细的把动态规划问题说明的很清楚,我决定还是拿出我的全部家当,来跟大家分享我对动态规划的理解,我会尽可能的把所遇到的动态规划的问题都涵盖进去,博主退役多年,可能有些地方会讲的不完善,还望大家多多贡献出自己的宝贵建议,共同进步~~~ 概念 首先我们得知道动态规划是什么东东,百度百科上是这么说的,动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数
Angel_Kitty
2018/04/08
4.6K0
浅谈我对动态规划的一点理解---大家准备好小板凳,我要开始吹牛皮了~~~
动态规划专题刷题记录④:状态机模型
先来解释什么是“状态”( State )。现实事物是有不同状态的,例如水,就有固液气三种状态。我们通常所说的状态机是有限状态机,也就是说被描述的事物的状态是有限的,水的状态就是三个——固液气。
Here_SDUT
2022/06/29
7850
动态规划专题刷题记录④:状态机模型
【愚公系列】2023年12月 五大常用算法(三)-动态规划算法
动态规划算法的基本思想是将原问题分解为若干个子问题,并先求解子问题,再根据子问题的解得到原问题的解。这种方法的优点在于避免了重复计算,从而提高了算法的效率。
愚公搬代码
2023/12/14
2581
动态规划篇——线性DP
动态规划篇——线性DP 本次我们介绍动态规划篇的线性DP,我们会从下面几个角度来介绍: 数字三角形 最长上升子序列I 最长上升子序列II 最长公共子序列 最短编辑距离 数字三角形 我们首先介绍一下题目: /*题目概述*/ 给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层 要求找出一条路径,使路径上的数字的和最大。 7 3 8 8 1 0 2 7 4 4
秋落雨微凉
2022/11/30
3700
【代码随想录】二刷-动态规划
动态规划 解题步骤: 确定dp数组 确定递推公式——递推公式决定dp数组要如何初始化 dp数组如何初始化 确定遍历顺序 举例推导dp数组 ---- 509. 斐波那契数 class Solution { public: int fib(int n) { if(n <= 1)return n; // 推导公式: dp[n] = dp[n-1]+dp[n-2] int dp[2]; // 初始化 dp[0] =
半生瓜的blog
2023/05/13
4940
动态规划入门
       动态规划是一种常见的算法设计方法,主要用于优化多阶段决策问题的求解过程,具有高效性和可靠性。其基本思想是将待求解问题分解成若干个子问题,逐个求解这些子问题,并保存每个子问题的结果,避免重复计算,以便快速地求出原问题的解。动态规划主要应用于最优化问题,如最长公共子序列、背包问题等。
周小末天天开心
2023/10/16
2570
动态规划入门
【蓝桥杯2022省赛】备赛蓝桥杯经典动态规划。背包问题、背包与魔法、李白打酒加强版
给你一个可装载重量为 W 的背包和 N 个物品,每个物品有重量和价值两个属性。其中第 i 个物品的重量为 w[i],价值为 v[i],现在让你用这个背包装物品,最多能装的价值是多少?
小小程序员
2023/02/08
5020
相关推荐
动态规划专题——背包模型
更多 >
LV.0
这个人很懒,什么都没有留下~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验