最长公共上升子序列

来源:互联网 发布:女网球运动服知乎 编辑:程序博客网 时间:2024/05/22 23:44


:

x,y,s,

si<sj(0<=i<j<|s|).S.

比较直观的做法(O(n^4))

仿dp[i][j],xi,yj.so,

if xi != yj    dp[i][j] = 0else    dp[i][j] = max(dp[ii][ij]) ( 0 <= ii < i, 0 <= ij < j, dp[ii][ij] != 0 && x[ii] < x[i]) + 1

O(n4)

O(n^3)的算法

LICSLISLCS.LISLCS.

LISdp[i]xi.

LCSdp[i][j]x[0i]y[0j].

LISdp[i]x[0i]?

LISdp[i],,x[i]

.LCSdp[i][j],.

LICS,LIS,,dp[i][j],xiyj

xi,yi,,,.

dp[i][j]x[0i]y[0j]LICS,yj.

so,

if xi != yj    dp[i][j] = dp[i-1][j]else    dp[i][j] = max(dp[i-1][k])(0 < k < j && y[k] < y[j]) + 1

:

x[0...m]y[0...n],y[n]z[0...zn].

x[m]!=y[n],z[0...zn]x[0...m1]y[0...n],y[n]LICS.

x[m]==y[n],z[0...zn1]x[0...m1]y[0...k],y[k]LICS(0<k<j),.

反证:设s, s[0...sn]为x[0...m-1]和y[0...k]上的, 以x[k]为结束的一个LICS, 并且sn > zn-1.那么,s[0...sn] 可以加上y[n], 得到长度sn+1的一个以y[n]为结束字符的最长公共上升子序列, sn+1 > zn, 与假设矛盾.

.

O(n3).

O(n^2)对O(n^3)的一个优化.

,dp[i][j]dp[k][j1](0<k<i).

ii.

i,,O(n2).

memset(dp, 0, sizeof(dp));for (i = 1; i <= m; i++) {    for(j = 1; j <= n; j++) {        dp[i][j] = 0;        if (x[i] != y[j]) {            dp[i][j] = dp[i-1][j];        } else {            for (k = 1; k < j; ++k) {                if (dp[i][j] < dp[i - 1][k] && y[k] < y[j]) {                    dp[i][j] = dp[i - 1][k];                }            }            dp[i][j] += 1;        }

,x[i]=y[j],dp[i][j].

O(n2).

:

for (k = 1; k < j; ++k) {    if (dp[i][j] < dp[i - 1][k] && y[k] < y[j]) {        dp[i][j] = dp[i - 1][k];    }}

y[j]=x[i],

for (k = 1; k < j; ++k) {    if (dp[i][j] < dp[i - 1][k] && y[k] < x[i]) {        dp[i][j] = dp[i - 1][k];    }}

dp[i1][k](0<k<j)y[k]<x[i]

i(),j,.

mlendp[i1][k](0<k<j)y[k]<x[i]

jO(1)mlendp[i][j].

:

for (i = 1; i <= m; i++) {    mlen = 0;    for(j = 1; j <= n; j++) {        dp[i][j] = dp[i-1][j];        //更新mlen        if (y[j] < x[i] && dp[i - 1][j] > mlen) {                mlen = dp[i - 1][j];        }        //计算dp[i][j]        if (y[j] == x[i]) {            dp[i][j] = mlen + 1;        }    }}

O(n2)

#include<iostream>#include<cstdio>#include<algorithm>using namespace std;int f[5005][5005];int a[5005],b[5005];int yh[5005];int pre[5005][5005];int main(){  int n;  scanf("%d",&n);  for (int i=1;i<=n;++i) scanf("%d",&a[i]);  int m;  scanf("%d",&m);  for (int i=1;i<=m;++i) scanf("%d",&b[i]);  int ans=0;    int x=n;    int y=m;  for (int i=1;i<=n;++i){      int len=0;      int last=0;    for (int j=1;j<=m;++j){        f[i][j]=f[i-1][j];            if (a[i]>b[j]&&f[i-1][j]>len) len=f[i-1][j],last=j;        if (a[i]==b[j]) f[i][j]=len+1,pre[i][j]=last;            if (f[i][j]>ans){              y=j;              ans=f[i][j];            }        }    }    printf("%d\n",ans);    int tail=0;    while(ans--){    yh[++tail]=b[y];    while(a[x]!=b[y]) x--;    y=pre[x][y];    x--;  }    for (int i=tail;i>=2;--i) printf("%d ",yh[i]);    printf("%d\n",yh[1]);  return 0;}
原创粉丝点击