题目链接:https://www.acwing.com/problem/content/description/274/

两个序列 a,b 求最长公共上升子序列

我们定义f[i][j]  为  a序列的前i个和b序列的前j个元素的最长公共上升子序列
那么  当前的f[i][j] 可以继承 f[i-1][j] 的状态。如果a[i] == b[j] 那么它可能的状态是f[i-1][j]的状态,也有可能是f[i][1 ~ j - 1]中的某个状态+1。

这个应该很容易理解出来,复杂度为n^3

code:

#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize(2)
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
const int nn = 3010;
int f[nn][nn];
int n;
int a[nn],b[nn];
int main()
{
	n = read();
	for(int i=1;i<=n;i++)	a[i] = read();
	for(int i=1;i<=n;i++)	b[i] = read();
	
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	{
		f[i][j] = f[i-1][j];
		if(a[i]==b[j])
		{
			f[i][j] = max(1,f[i][j]);
			for(int k=1;k<j;k++)
				if(b[k]<b[j])
				{
					f[i][j] = max(f[i][j],f[i][k]+1);
				}
		}
	}
	int res = 0;
	for(int i=1;i<=n;i++) res = max(res,f[n][i]);
	cout<<res<<endl;
}


 

改进版:在上一个代码的情况下,我们发现  a[i]==b[j]的时候才会去考虑1 - j-1的状态,所以if(b[k]<b[j]) 可以 等价替换为 if(b[k]<a[i])
我们考虑  b[k]为  1~j-1的某个状态。而1~j-1是和第二层的循环顺序是一样的。而它的目的就是求1~j-1其中一个最优状态。所以我们在遍历二层循环的时候可以找一个变量记住每次最优状态。且当a[i] == b[j]时我们进行转移,最优状态的这个这个变量最少为1,因为每次相等时,这个状态至少为1.

code:

#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize(2)
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
const int nn = 3010;
int f[nn][nn];
int n;
int a[nn],b[nn];
int main()
{
	n = read();
	for(int i=1;i<=n;i++)	a[i] = read();
	for(int i=1;i<=n;i++)	b[i] = read();
	
	for(int i=1;i<=n;i++)
	{
		int tmax = 1;
		for(int j=1;j<=n;j++)
		{
			f[i][j] = f[i-1][j];
			if(a[i]==b[j]) f[i][j] = max(f[i][j],tmax);
			if(b[j]<a[i])
				tmax = max(f[i][j]+1,tmax);
		}
	}
	
	int res = 0;
	for(int i=1;i<=n;i++) res = max(res,f[n][i]);
	cout<<res<<endl;
}