【poj2127】 Greatest Common Increasing Subsequence

http://poj.org/problem?id=2127 (题目链接)

题意

  计算两个序列$a$和&b$的最长公共上升子序列。

Solution

  爸爸的$n^3$算法莫名其妙RE了,不爽之下学习了一发$n^2$的。

  http://www.cnblogs.com/dream-wind/archive/2012/08/25/2655641.html

  $f[i][j]$表示序列$a$的前$i$位,序列$b$的前$j$位,以$b_j$结尾的最长公共上升子序列长度。

  转移:$$f[i][j]=f[i-1][j](a_i!=b_j)$$

$$f[i][j]=max_{1<=k<j}f[i-1][k]+1(a_i=b_j)$$

  这样直接做的话是$n^3$的,我们用前缀最大值优化一下,然后记录方案即可。

代码

// poj2127
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf (1ll<<60)
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxn=1000;
int a[maxn],b[maxn],f[maxn][maxn],p[maxn][maxn],ans[maxn];
int n,m;

int main() {
	while (scanf("%d",&n)!=EOF) {
		for (int i=1;i<=n;i++) scanf("%d",&a[i]);
		scanf("%d",&m);
		for (int i=1;i<=m;i++) scanf("%d",&b[i]);
		int sum=0,ai,aj;
		for (int i=1;i<=n;i++) {
			int mx=0,mj=0;
			for (int j=1;j<=m;j++) {
				f[i][j]=f[i-1][j];
				p[i][j]=-1;
				if (b[j]<a[i] && f[i-1][j]>mx) mx=f[i-1][j],mj=j;
				else if (a[i]==b[j]) f[i][j]=mx+1,p[i][j]=mj;
				if (sum<f[i][j]) sum=f[i][j],ai=i,aj=j;
			}
		}
		printf("%d\n",sum);
		int tmp=sum;
		for (;ai;ai--) if (p[ai][aj]>-1) ans[tmp--]=b[aj],aj=p[ai][aj];
		for (int i=1;i<=sum;i++) printf("%d ",ans[i]);
		puts("");
	}
    return 0;
}

 

posted @ 2017-02-20 10:23  MashiroSky  阅读(313)  评论(1编辑  收藏  举报