【模板题】动态规划 NOI 2000:最长公共子上升序列

折磨人的一道题。。。花了一天时间。题目来源:点击打开链接

题目大意:a,b数组中,找一个最大公共子序列,并且该序列是递增的

找ans不难,重点在保存序列。注意的地方在注释里。

在理解题目的时候参考了点击打开链接,解释的很清楚。

代码如下:

#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
using namespace std;
long long a[501],b[501],z[501];
int dp[501][501]={0},pre[501][501];
int main()
{
	int n,m,i,ans,j,mx,locay;
	cin>>m;
	for (i=1;i<=m;i++)//一定要按输入例子的顺序。。。也不知道为什么,说好的任意一个序列呢!
		cin>>b[i];
	cin>>n;
	for (i=1;i<=n;i++)
		cin>>a[i];
	ans=0;
	for (i=1;i<=n;i++)
	{
		mx=0;locay=0;
		for (j=1;j<=m;j++)
		{
			dp[i][j] = dp[i-1][j];//忘记加了!首先要保证到i、j为止的最大长度不可能小于i-1,j的
			pre[i][j] = j;//只要以一个序列为准记住pre就可以
			//i不变,遍历j,此时要保证j序列值要小
			//才可以是上升序列(即把k的循环查找条件调到外面)
			if (a[i]>b[j] && mx<dp[i-1][j])
			{	
				mx=dp[i-1][j];//记录dp[i-1][0~j]的最大值,可以省去内层k的循环
	            locay=j;//记录此时的j值
			}
			else if (a[i]==b[j]) 
			{
				dp[i][j]=mx+1;
				pre[i][j] = locay;
			}
			ans=max(ans,dp[i][j]);
		}
	}
	cout<<ans<<endl;
	int t=1;
	for (j=2;j<=m;j++)//看作一位数组,找最大的序列的末尾为止,也可以在上面的ans更新时记住
		if (dp[n][j]>dp[n][t])
			t=j;
	int top=0;
	i=n;j=t;
	while (dp[i][j])//=0为止
    {
		 while(a[i]!=b[j]&&i) i--;//找到一个相等的值为止
		 z[top++]=b[j];
		 j=pre[i][j];
    }
	for (i=top-1;i>=0;i--)
		cout<<z[i]<<" ";
	cout<<endl;
	return 0;
}


猜你喜欢

转载自blog.csdn.net/always_ease/article/details/80502598