动态规划+深度优先搜索+记忆化搜索(干货满满)

本文介绍了动态规划的概念,包括无后效性、最优子结构和子问题重叠性质,并阐述了动态规划求解问题的一般思路。通过最长上升子序列、最长公共子序列问题来加深理解。此外,文章还探讨了数字三角形问题中使用深度优先搜索和记忆化搜索的方法,强调动态规划与贪心算法的区别,并分享了个人对动态规划的理解。
摘要由CSDN通过智能技术生成

动态规划的定义

动态规划算法与分治法的思想类似,都是通过组合子问题的解来求原问题。我先来给大家介绍一下分治思想,分治思想就是把一个复杂的问题,分解为k个规模相同的子问题,如果还是无法解决,子问题又可以分为若干个相同规模的子问题求解,之后组合求原问题(难点)如二分法,归并排序,折半查找。至于动态规划:就是一个最优化问题,先将问题分解为子问题,并且对于这些分解的子问题自身就是最优的才能在这个基础上得出我们要解决的问题的最优方案(假设最优然后去求),要不然的话就能找到一个更优的解来替代这个解,得出新的最优自问题,这当然是和前提是矛盾的。同于 贪心算法,因为贪心算法是从局部最优来解决问题,而动态规划是全局最优的。用动态规划的时候不可能在子问题还没有得到最优解的情况下就做出决策,而是必须等待子问题得到了最优解之后才对当下的情况做出决策,所以往往动态规划都可以用 一个或多个递归式来描述。而贪心算法却是先做出一个决策,然后在去解决子问题。这就是贪心和动态规划的不同。

–摘自剑锋OI博文

  • 动态规划求解问题的三个基本条件
    1)无后效性: 动态规划要求已经求解的子问题不受后续阶段的影响,以保证对每一阶段的计算能够按顺序、不重复地执行。
    2)最优子结构性质: 在动态规划算法求解问题的过程中,下一阶段的解应该能由前面各阶段子问题的最优解导出。
    3)子问题重叠性: 动态规划所针对的问题还有另外一个显著的特征,即它所对应的子问题树中的子问题呈现大量的重复,称为子问题重叠性质。
  • 用动态规划求解问题的一般思路
    1)首先要确定子问题的状态,这是一个关键(即确定dp数组代表的含义是什么)。
    2)确定状态转移方程(可用于计算各阶段同类子问题的计算公式)进而求解原问题。
    动态规划和贪心类似,都没有固定的解题模板,只能通过多刷题,多分析来确定问题的状态转移方程(重点),进而求解问题。
    下面我们通过做一些题目来进一步理解动态规划。

最长上升子序列问题

在这里插入图片描述
题目出自SDUTOJ
题解:
我们要求最长上升子序列的长度,自然要挨个数字来寻找,这时我们用dp[i]来表示用i个数字结尾的最长上升子序列的长度。
样例 1 7 3 5 9 4 8
dp[i] 1 2 2 3 3 …
dp[2]:
dp[2]=dp[1]+1;
dp[3]:
dp[3]=dp[1]+1;
dp[4]:
dp[4]=dp[1]+1;
dp[4]=dp[3]+1;
这时我们发现了什么规律呢?
没错从第一位数字开始寻找,找到一个比当前的数小的数就+1更新一下,直到遍历到当前数字。
我们就得到状态转移方程
dp[i]=max( dp[j] + 1, dp[i] ) 0<j<i;

#include <iostream>
using namespace std;

const int N=1000;
int a[N],dp[N];

int main()
{
   
	int n;
	int res=0;
	cin>> n;
	dp[0]=0;
	a[0]=-1;  //注意这里为什么要让a[0]=-1?还是说让a[0]小于某个数就行?  继续往下看
	for(int i=1;i<=n;i++)
	{
   
		cin>>a[i];
		for(int j=0;j<i;j++){
   
			if(a[j]<a[i]){
        //这里我们第一次发现了a数组的比较  j从0开始也就发现了上面关于a[0]的问题
			//我们注意到a[i]任意一个数是大于等于0的而a[0]是负数  结合下面的代码我们发现其目的就是在于解决最小上升子序列的长度为1的情况
				dp[i]=max(dp[i],dp[j]+1);
			}
		}
		res=max(res,dp[i]);
	}
	cout<<res<<endl;
	return 0;
}

shi最长公共子序列问题(LCS问题)

在这里插入图片描述
题目源自SDUTOJ
题解:
状态表示:我们用dp[i][j]表示数字A[1,i]与B[1,j] 的最长公共子序列长度。
分析:
当s1[i]=s2[j]时 dp[i][j]=d[i-1][j-1]+1; 因为相同时肯定是最长公共子序列长度+1;
当s1[i]!=s2[j]时 dp[i][j]=max(dp[i][j-1],dp[i-1][j]) 举个例子:
ABC A
ABD C
可得dp[4][4]=dp[3][4];

#include <iostream>
#include <string.h>
using namespace std;
const int N=505;
int dp[N][N];
char s1[N],s2[N];

  • 14
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值