week10作业——B:LIS & LCS

主要思路:

课上的例题,得到转移方程以后便很好实现了(这也是动态规划的特点)

LIS :

记dp[ i ]表示以第i个元素结尾的LIS(注意,这里的定义意味着第i个元素是一定被包括进去的),所以dp[i]的值至少是1,这也是合情合理的
此时,我们需要检验第i个元素是否能够插入到之前的某个LIS中去,所以我们遍历 i 之前的 i-1 个元素,比较第i个元素和当前遍历到的元素的大小,更新 dp[ i ] = max{ dp[ j ]+1 } for j in [ 1, i-1 ]
需要循环n*(n-1)/2次,复杂度:O(n2)

LCS :

记dp[ i ] [ j ]表示 A序列的前 i 个元素LCS长度、 B序列的前 j 个元素LCS长度
转移方程:
当 a[ i ] == b[ j ]时,dp[ i ] [ j ] = dp[ i-1 ] [ j-1 ]+1
否则 dp[ i ] [ j ] = max{ dp[ i-1 ] [ j ], dp[ i ] [ j-1 ] }

即,遇到了相同的数字,满足题意即可更新答案+1

B:LIS & LCS

东东有两个序列A和B。
他想要知道序列A的LIS和序列AB的LCS的长度。
注意,LIS为严格递增的,即a1<a2<…<ak(ai<=1,000,000,000)。

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

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

Sample Input

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

Sample Output

3 2

A Possible Solution

#include<stdio.h>

const int maxn=5e3+2;
int a[maxn],b[maxn],N,M;
int ans1=0,ans2=0;
int dp1[maxn],dp2[maxn][maxn];

int main(){
	
	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);
		
	dp1[1]=1;
	for(int i=2;i<=N;i++){
		int tmp=0;
		for(int j=1;j<i;j++){
			if(a[j]>=a[i])continue;
			tmp=tmp<dp1[j]?dp1[j]:tmp;
		}
		dp1[i]=tmp+1;
	}
	for(int i=1;i<=N;i++)
		ans1=ans1<dp1[i]?dp1[i]:ans1;
	
	/**********分割线***********/
	
	dp2[0][0]=0,dp2[1][0]=0,dp2[0][1]=0;
	for(int i=1;i<=N;i++){
		for(int j=1;j<=M;j++){
			if(a[i]==b[j])dp2[i][j]=dp2[i-1][j-1]+1;
			else{
				dp2[i][j]=dp2[i-1][j]>dp2[i][j-1]?dp2[i-1][j]:dp2[i][j-1];
			}
		}
	}
	ans2=dp2[N][M];
	
	printf("%d %d\n",ans1,ans2);
		
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值