我眼中的--线性动规

线性动规(线性dp)

一.什么叫线性dp

我觉得就像线性结构一样,具有一对一的邻接逻辑关系,简单来说就是n个数据元素的有序集合;
线性dp也就是在线性结构上的递推,所解决的问题也就像LIS和LCS一样。
LIS:最长上升子序列问题;
LCS:最长公共子序列问题。

二.线性dp的思路

线性动规也是一种动态规划,所以他的思路也是把多阶段问题划分成单阶段的子问题。例如LIS问题,你可以把他的长度划分成不同的阶段,只有两个字符时,只有三个字符时等…然后逐步递推,借助转移方程来进行转移,最后求出问题答案。

三.线性dp的例题详解

例如:1759:最长上升子序列

(1)题目要求:

一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).

你的任务,就是对于给定的序列,求出最长上升子序列的长度。

(2)输入与输出:

输入:
输入的第一行是序列的长度N (1 <= N <= 1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000。
输出:
最长上升子序列的长度。
样例输入:
7
1 7 3 5 9 4 8
样例输出:
4

(3)解析

1.具体问题具体分析。
2.划分阶段。
不同的长度阶段下有不同的状态;

3.确定状态变量。
i—控制长度变量;
j—当前第几个字符;
dp[i]表示以a[i]结尾的最长上升子序列的长度 。

4.建立各阶段状态变量的转移过程,确定状态转移方程。

1 7 3 5 9 4 8
初始化 0 0 0 0 0 0 0
1 1 0 0 0 0 0 0
2 1 2 0 0 0 0 0
3 1 2 2 0 0 0 0
4 1 2 2 3 0 0 0
5 1 2 2 3 4 0 0
6 1 2 2 3 4 3 0
7 1 2 2 3 4 3 4

所以我们通过表得出转移方程:

 dp[i]=max(dp[i],dp[j]+1);
 	//转移方程;

5.确定终止条件。
由上表我们可以得到递推的终止条件j<i;

另外因为我们由上表得到最后一次dp[i]就是每个a[i]的最长上升子序列,所以我们要求全部最长的时候,应该要求dp的最大值;
代码如下:

int maxx=dp[1];
	for(int i=2;i<=n;i++) 
		maxx=max(maxx,dp[i])

四.完整代码

#include<stdio.h>
#include<string.h>
#define N 100001
int max(int a,int b)
{
	if(a>=b)
		return a;
	return b;
}
int main()
{
	int a[N],dp[N];
	int n;
    scanf("%d",&n);
    memset(dp,0,sizeof(dp));
    
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
        
    dp[1]=1;
    	//把第一次填表简化为dp[1]=1;
    for(int i=2;i<=n;i++)
        for(int j=1;j<i;j++)
	        if(a[j]<a[i]) 
				dp[i]=max(dp[i],dp[j]+1); 
				//转移方程;
	int maxx=dp[1];
	for(int i=2;i<=n;i++) 
		maxx=max(maxx,dp[i]);
		//找出最大值;
    printf("%d",maxx);
    return 0;
}
发布了12 篇原创文章 · 获赞 7 · 访问量 1453

猜你喜欢

转载自blog.csdn.net/weixin_45843077/article/details/104194693
今日推荐