WEEK10 周记 作业——动态规划_LIS & LCS问题

本文深入解析动态规划中两个经典问题:最长递增子序列(LIS)和最长公共子序列(LCS)的算法原理及实现。通过实例讲解状态转移方程,提供C++代码示例,帮助理解并掌握这两种算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

WEEK10 周记 作业——动态规划_LIS & LCS问题

一、题意

1.简述

东东有两个序列A和B。

他想要知道序列A的LIS和序列AB的LCS的长度。

注意,LIS为严格递增的,即a1<a2<…<ak(ai<=1,000,000,000)。

2.输入格式

第一行两个数n,m(1<=n<=5,000,1<=m<=5,000)
第二行n个数,表示序列A
第三行m个数,表示序列B

3.输出格式

输出一行数据ans1和ans2,分别代表序列A的LIS和序列AB的LCS的长度

4.样例

Input

5 5
1 3 2 5 4
2 4 3 1 5

Output

3 2

二、算法

主要思路

LIS 最长上升子序列

给定 n 个整数 Ai,A2,…,AnA_i, A_2,…, A_nAi,A2,,An,按从左到右的顺序选出尽量多的整数,组成一个上升子序列。输出最长上升子序列的长度。
例如,序列 1,6,2,3,7,5上升子序列可以是1,6,7,;也可以是 1,2,3,5。而 最长上升子序列为 1,2,3,5,其长度为 4,故 ans = 4
求解其长度的状态转移方程为:
f1=1f_1=1f1=1fi=max{fj∣j<i⋀Aj<Ai}+1,i≥2fi=max\{f_j|j<i \bigwedge A_j<A_i\}+1,i\ge2fi=max{fjj<iAj<Ai}+1,i2
那么最终的LIS的长度为maxf[i],i=1…nmax{f[i], i=1…n}maxf[i],i=1n
算法时间复杂度为O(n2)O(n^2)O(n2)


LCS 最长公共子序列

给两个序列 A 和 B,求长度最大的公共子序列的长度
例如:
A – 1,5,2,6,8,7
B – 2,3,5,6,9,8,4
最长公共子序列为:
A – 1,5,2,6,8,7
B – 2,3,5,6,9,8,4

A – 1,5,2,6,8,7
B – 2,3,5,6,9,8,4
f[i][j]f[i][j]f[i][j]A1,A2,…,AiA_1, A_2, …, A_iA1,A2,,AiB1,B2,…,BjB_1, B_2, …, B_jB1,B2,,Bj 的 LCS 长度
状态转移方程f[1][0]=f[0][1]=f[0][0]=0f[1][0] = f[0][1] = f[0][0] = 0f[1][0]=f[0][1]=f[0][0]=0f[i][j]=f[i−1][j−1]+1,Ai=Bjf[i][j] = f[i-1][j-1] + 1,Ai = Bjf[i][j]=f[i1][j1]+1,Ai=Bjf[i][j]=max(f[i−1][j],f[i][j−1]),Ai≠Bjf[i][j] = max(f[i-1][j], f[i][j-1]),A_i\ne B_jf[i][j]=max(f[i1][j],f[i][j1]),Ai=Bj
输出答案:f[n][m]f[n][m]f[n][m]
时间复杂度:O(nm)O(nm)O(nm)


三、代码

#include<iostream>
#include<cstring>
#include<string>
using namespace std;
int a[5010];  //从1开始 
int b[5010];  //从1开始
int n,m;
int ans1,ans2;
int lth1[5010]; //从1开始
int f[5010][5010];  //从1,1开始
int main(){
	f[0][0] = 0; 
	f[0][1] = 0;
	f[1][0] = 0;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=m;i++) scanf("%d",&b[i]);
	
	//求ans1
	for(int i=1;i<=n;i++){
		lth1[i] = 1;
		for(int j=1;j<i;j++){
			if(a[j]<a[i]&&lth1[i]<lth1[j]+1) lth1[i] = lth1[j]+1;
		}
	}
	for(int i=1;i<=n;i++)
		if(lth1[i]>ans1) ans1 = lth1[i];
	
	//求ans2
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(a[i]==b[j]) f[i][j] = f[i-1][j-1]+1;
			else{
				f[i][j] = f[i-1][j]>f[i][j-1]?f[i-1][j]:f[i][j-1];
			}
		}
	}
	ans2 = f[n][m];
	printf("%d %d",ans1,ans2);
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值