动态规划概述

news2025/2/27 13:57:21

动态规划概述

动态规划的两个要求:

1.最优子结构

例:现有一座10级台阶的楼梯,我们要从下往上走,每次只能跨一步,一步可以往上走1级或者2级台阶,请问一共有多少种解法呢?

台阶数12345678910
走法数123581321345589

可以发现,我们都可以通过前两个状态来推出当前状态

**最优子结构:**大问题的(最优)解可以由小问题的(最优)解来推出,在这个问题当中,大问题的f(n)的解可以由小问题f(n-2)和f(n-1)的解推出。注意:在问题拆解过程当中不能无限递归

2.无后效性

未来与过去无关,一旦得到了一个小问题的解,如何得到它的解的过程不会影响到大问题的求解。在上面这个问题种,我们只需要知道f(n-1)和f(n-2)的值,但是怎么得到它的已经不重要了。

动态规划的两个元素:

状态:

求解过程进行到了哪一步,可以理解为一个子问题。

转移:

从一个状态(小问题)的(最优)解推导出另一个状态(大问题)的(最优)解的过程。

最短路I

最短路

最优子结构:为了计算出从1号点到y号点最少花费的时间,我们可以计算出所有与y号点所连接的边,并且标记所有小于y的点x,从1号点到x号点所花费的最短时间,最后再推到y号点的情况。

无后效性:我们只关心每个点所花费的最短时间,不关心到底是怎么走到这个点的。

状态:f[i]表示从1i所花费的最短时间

转移:假设已经知道了f[x]的值,并且存在一条从xy的代价为z的边,那么可以推导出方程:f[y]=min(f[y],f[x]+z)

AC代码:
#include<iostream>
using namespace std;
const int N = 1010;
int a[N][N], f[N], n, m;//a数组存图

int main(void)
{
	cin >> n >> m;
	memset(a, 127, sizeof(a));//将a的每一条边都初始化为一个很大的值
	for (int i = 1; i <= m; i++)
	{
		int x, y, z;
		cin >> x >> y >> z;
		a[x][y] = min(a[x][y], z);//防止有重边
	}
	memset(f, 127, sizeof f);
	f[1] = 0;
	for (int i = 2; i <= n; i++)
	{
		for (int j = 1; j < i; j++)
		{
			if (f[j] < 1 << 30 && a[j][i] < 1 << 30)
				f[i] = min(f[i], f[j] + a[j][i]);
		}
	}
	cout << f[n];
	return 0;
}

最短路II

最短路2

这里存在无限递归,因为每一次绕着1 2 4 3走一圈代价就会减少5,所以不能使用动态规划解决

最长上升子序列

最长上升子序列

最优子结构:为了计算a[i]i结尾的最长上升子序列的长度,我们可以通过枚举所有小于i的位置j,我们可以先计算出以a[j]结尾的上升子序列,然后判断a[i]是否大于a[j],如果a[i]>a[j]那么答案就是a[j]+1,反之答案就是a[j]

无后效性:我们只关心以i这个位置结尾的最长上升子序列的长度,并不关心子序列是什么。

状态:用f[i]表示以i结尾的最长上升子序列的长度

转移:对于某个位置i,为了计算i,我们枚举子序列种所有小于i的元素j,满足j<i&&a[j]<a[i]可以得到状态转移方程:f[i]=max(f[i],f[i]+1)

序号12345678910111213141516
a1314171278192352116915520131410
f1231123453134674

最后答案等于f[i]当中的最大值

AC代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n, a[N], f[N];

int main(void)
{
	cin >> n;
	int res = -10;
	for (int i = 1; i <= n; i++) cin >> a[i];
	for (int i = 1; i <= n; i++)
	{
		f[i] = 1;//如果没有找到能够满足子序列的,那么它的f[i]值就是1,需要初始化一下
		for (int j = 1; j < i; j++)
		{
			if (a[j] < a[i])
			{
				f[i] = max(f[i], f[j] + 1);
				if (f[i] > res) res = f[i];
			}
		}
	}
	cout << res;
	return 0;
}

最长公共子序列

最长公共子序列

最优子结构:为了计算出a[i]和b[j]的最长公共子序列,可以从a[i-1]a[j-1]来转移过来。

假如a[i]==a[j]那么我们可以从f[i-1][j-1]+1转移过来,就是考虑a的前i个元素b的前j个元素

假如a[i]!=a[j]那么可以从f[i-1][j]和f[i][j-1]转移过来,就是考虑a的前i-1个元素b的前j个元素以及a的前i个元素b的前j-1个元素

这时候可能就有人会有疑问,为什么不考虑f[i-1][j-1]的情况呢?

举一个例子:

a:ADABCABCD
i
b:DBABCCDAB
j

如上面的这个表格,如果a[i]!=a[j]那么有没有ij的元素,对前面的子串都是没有影响的。

aADABCAADABCDBABCC去比较都是一样的,所以f[i-1][j-1]的这种情况已经被包含在

f[i-1][j]f[i][j-1]当中了。

无后续性:我们只在乎最长公共子序列的长度是多少,至于是哪些元素构成的我们并不在乎

状态:f[i][j]表示a以第i个位置结尾b以第j个位置结尾的最长公共子序列是多少。

转移:如果a[i]==a[j]那么f[i][j]=f[i-1][j-1]+1

​ 如果a[i]!=a[j]那么f[i][j]max(f[i-1][j],f[i][j-1])

AC代码:

#include<iostream>
using namespace std;
const int N = 1010;
int n, m, a[N], b[N], f[N][N];

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

思考题:最长回文子串

最长回文子串

状态:f[i][j]表示从i到j是否满足回文,如果f[i][j]要满足回文字符串的条件,我们可以从

f[i+1][j-1]推到过来,如果f[i+1][j-1]满足回文子串,那么只要str[i==str[j],就可以判定

f[i][j]是回文字符串, 那么如何去得到f[i+1][j-1]的状态呢,我们可以通过不断改变字符串的长度,来判断不同长度字符串的所有情况是否满足是回文子串,比如我要看是否存在长度为4的回文字符串,那么就可以先去找长度为2的,最后判断边界是否相等(str[i]==str[j])即可。

转移:如果str[i]==str[j]那么 f[i][j]=f[i+1][j-1],反之f[i][j]=false

AC代码:

#include<iostream>
using namespace std;
const int N = 1010;

bool f[N][N];
int main(void)
{
	string str;
	cin >> str;
	int len = str.size();

	for (int i = 0; i <= len; i++)
	{
		f[i][i] = true;//将一个字符的全都初始化为true
	}

	int begin = 0,maxlen=-10010;

	for (int l = 2; l <= len; l++)//从长度为2开始计算状态,找到满足回文的子串
	{
		for (int i = 0; i < len; i++)
		{
			int j = l + i - 1;
			if (j >= len) break;

			if (str[i] != str[j]) f[i][j] = false;
			else
			{
				if (j - i < 3)
				{
					f[i][j] = true;
				}
				else
				{
					f[i][j] = f[i + 1][j - 1];
				}
			}
			if (f[i][j] && j - i + 1 > maxlen)
			{
				maxlen = j - i + 1;
				begin = i;
			}
		}
	}
	
	cout << str.substr(begin, maxlen);

	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/412791.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手动挡科目三道路驾驶技能考试及理论考试要点

路线每个驾校的科目三路线可能都不一样&#xff0c;但是考点基本差不多。我当时选的驾校是北京公交驾校&#xff0c;路线图如下&#xff1a;考试要点在考试大厅等待叫号&#xff0c;一般大屏都会公布xxx学员找xx号车考试&#xff0c;这边白色车是手动挡&#xff0c;灰色车是自动…

Web自动化测试-【Selenium环境部署Edge】

Selenium Web自动化测试工具 之前写过一篇关于自动化测试的博客&#xff0c;里面是有的chrome驱动&#xff0c;由于不适配缘故&#xff0c;更新以下Edge驱动。 自动化测试 Selenium环境部署 准备 Edge 浏览器准备 Edge 驱动包 a .查看自己的Edge浏览器版本&#xff08;浏览器版…

【论文解读】ConvNeXt V2: Co-designing and Scaling ConvNets with Masked Autoencoder

1. 本文贡献 提出了一个全卷积掩码的自动编码器框架和一个新的全局响应归一化&#xff08;GRN&#xff09;层 1.1 想法 本文的想法是希望能在 ConvNeXt 中使用MAE,但是MAE的设计架构是基于vision transformer的&#xff0c;与使用密集滑动窗口的标准ConvNets不兼容&#xf…

upload 通关pass16-pass20

1.pass16 白名单 二次渲染 需要先上传一个正常图片&#xff0c;然后下载下来&#xff0c;跟原图片进行比对&#xff0c;用010 16进制编辑器&#xff0c;把php代码放到没有改变的位置&#xff0c;即一样的地方 访问&#xff1a; 2.pass17 白名单 条件竞争 这题先是上传文件并…

音质蓝牙耳机哪款好用?2023公认音质好的四款蓝牙耳机推荐

现如今&#xff0c;蓝牙耳机越来越受欢迎&#xff0c;不少人在听歌、追剧、甚至是玩游戏的时候都会戴着它。最近看到很多人问&#xff0c;音质蓝牙耳机哪款好用&#xff1f;针对这个问题&#xff0c;我来给大家推荐四款公认音质好的蓝牙耳机&#xff0c;一起来看看吧。 一、南…

Nginx connect req access 模块

Nginx connect req access 模块演练 limig_conn模块&#xff1a;限制TCP连接数limit_req模块&#xff1a;限制请求频率access 模块&#xff08;allow/deny&#xff09;&#xff1a;限制ip段访问auth_request: 基于HTTP响应状态码做权限控制压测可以使用 postman的 run collect…

AndroidStudio如何进行手机应用开发?

文章目录0、引言1、AndroidStudio开发环境配置2、创建第一个手机应用0、引言 Android手机应用因其搭载于手机&#xff0c;使用便捷&#xff0c;应用被大量开发使用。笔者使用手机多年&#xff0c;用过许多手机软件&#xff0c;在使用的过程中&#xff0c;虽然手机软件能解决大部…

C++开发必知的内存问题及常用的解决方法-经典文章

1. 内存管理功能问题 由于C语言对内存有主动控制权&#xff0c;内存使用灵活和效率高&#xff0c;但代价是不小心使用就会导致以下内存错误&#xff1a; • memory overrun&#xff1a;写内存越界 • double free&#xff1a;同一块内存释放两次 • use after free&#xff1…

【数据结构】二叉树顺序结构及实现

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a;初阶数据结构 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对…

Surfshark下载到使用完整教程|2023最新

2023年3月16日更新 在正式介绍surfshark的教程( 教程直达学习地址: qptool.net/shark.html )之前&#xff0c;我们可以来看看最近surfshark的服务与产品退化到什么程度了。我曾经是Surshark两年的忠实用户&#xff0c;但是&#xff0c;现在&#xff0c;作为一个负责人的测评&a…

PostMan动态参数及循环调用

最近需要在测试环境批量创建es索引&#xff0c;也就是某个接口需要循环调用且参数还是变化的&#xff0c;但是我又不想写代码和脚本&#xff0c;于是研究了一下postman一些好玩的功能&#xff0c;希望能节约大家的开发时间 一.设置请求参数 1.获取创建索引的请求以及参数&…

ELK+Filebeat日志分析系统

目录 一.ELK基本介绍 1.ELK是什么&#xff1f; 2.组件简介 2.1 ELK组件介绍 2.2 ELFK组件介绍 2.3 其它组件 4.使用ELK的原因 5.完整日志系统的基本特征 二.Elasticsearch的介绍 三.Logstash的介绍 四.Kibana的介绍 五.ELK的工作原理 六.部署ELK日志分析系统 1.环…

0基础学习软件测试有哪些建议

其实现在基础的资料和视频到处都是&#xff0c;就是看你有没有认真的去找学习资源了&#xff0c;去哪里学习都是要看你个人靠谱不靠谱&#xff0c;再好的教程和老师&#xff0c;你自己学习不进去也是白搭在正式选择之前&#xff0c;大可以在各种学习网站里面找找学习资源先自己…

springboot+vue动物园管理系统java

本系统使用的角色主要有系统管理员、注册用户&#xff0c;本系统分为系统前台和系统后台&#xff0c;首先在系统前台&#xff0c;游客用户可以经过账号注册&#xff0c;管理员审核通过后&#xff0c;用账号密码登录系统前台&#xff0c;查看论坛交流、动物展览、原生动物展览、…

HTML5 <head> 标签、HTML5 <i> 标签

HTML5 <head> 标签 实例 HTML5 <head> 标签表示文档的头部&#xff0c;其中包含了与该文档有关的信息&#xff01; 一份在头部带有 <title> 标签的 HTML 文档&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"utf-8&…

Linux信号sigaction / signal

Linux信号sigaction / signal 文章目录Linux信号sigaction / signal目的函数原型struct sigaction信号枚举值ISO C99 signals.Historical signals specified by POSIX.New(er) POSIX signals (1003.1-2008, 1003.1-2013).Nonstandard signals found in all modern POSIX system…

虹科教您 | 基于Linux系统的RELY-TSN-KIT套件操作指南(1)——硬件设备与操作环境搭建

RELY-TSN-KIT是一款针对TSN的开箱即用的解决方案&#xff0c;它可以无缝实施确定性以太网网络&#xff0c;并从这些技术复杂性中抽象出用户设备和应用。该套件可评估基于IEEE 802.1AS同步的时间常识的重要性&#xff0c;并借助时间感知整形器来确定性地交付实时流量&#xff0c…

判断完全二叉树(层序遍历)| C

层序遍历 基本思路&#xff1a;利用队列&#xff0c;出上一层&#xff0c;带下一层&#xff08;NULL不入队列&#xff09; &#xff08;C语言需要自己构建队列→【队列】&#xff1c;用链表实现队列&#xff1e; | [数据结构] | C语言&#xff09; 代码 #include "Queu…

代码自动发布系统

之前是jenkins发现gitlab代码更新了就自动获取直接部署到服务器 现在是jenkins自动获取Code之后打包成镜像上传到仓库然后通知docker去拉取更新的镜像 分析 旧∶ 代码发布环境提前准备&#xff0c;以主机为颗粒度静态 新: 代码发布环境多套&#xff0c;以容器为颗粒度编译 …

Typora设置修改字体颜色快捷键

目录 1.typora如何设置修改字体颜色快捷键 2. AutoHotKey软件安装 3.typora关于AutoHotKey的具体操作 1.typora如何设置修改字体颜色快捷键 typora本身是不能直接修改字体颜色的&#xff0c;不过若是想修改还是可以用一些代码去改变的&#xff0c;但是每次都修改一次实在麻烦…