dpPOJ 2027 LCIS(最长上升公共子序列)

题意和解析见代码最后部分


#include<iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int a[505],b[505];
int dp[505][505];
int n,m;
int path[505][505];
int I,J,ans,res[505];

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        for(int i = 0 ; i < n ; i++)
        {
            scanf("%d",&a[i]);
        }
        scanf("%d",&m);
        for(int i = 0 ; i < m ; i++)
        {
            scanf("%d",&b[i]);
        }
        for(int i = 0 ; i <= n ; i++)
        {
            dp[i][0] = 0 ;
        }
        for(int j = 0 ; j <= m ; j++)
        {
            dp[0][j] = 0 ;    //字符都是计算的从1开始的,所以这些都是0,初始化
        }
        int ans = 0 ;
        memset(path,-1,sizeof(path));
        for(int  i = 1 ; i <= n ; i++)
        {
            for(int  j = 1 ; j <= m ; j++)
            {
                dp[i][j]=dp[i-1][j];
                if(a[i-1]==b[j-1])
                {
                    int maxnn=0;
                    for(int k=1;k<j;k++)
                    {
                        if(b[k-1]<b[j-1]&&dp[i][maxnn]<dp[i][k])
                        {
                            maxnn=k;
                        }
                    }
                    if(dp[i][maxnn]+1 > dp[i][j])
                    {
                        dp[i][j]=dp[i][maxnn]+1;
                        path[i][j]=maxnn;
                        if(dp[i][j] > ans)
                        {
                            ans=dp[i][j];
                            I=i;
                            J=j;
                        }
                    }
                }
            }
       }
       printf("%d\n",ans);
       int k=ans;
       while(ans)
       {
           if(path[I][J]>=0)
           {
                res[ans--]=b[J-1];
                J=path[I][J];
           }
           I--;
       }
       for(int i = 1 ; i <= k ; i++)
           printf("%d ",res[i]);
       printf("\n");
    }
    return 0;
}




/*
Auther:LIUYAN
2015.12.01

POJ 2027 LCIS(最长上升公共子序列)
并且将选择的数字输出

思路:
假如将dp[i][j]定义为第一个字符串的前i个字符和第二个字符串的前j个字符
中的最长上升子序列的话,递推结果为:
if(a[n]==b[m]) dp[n][m] = max(dp[i][j]) + 1 ;(i<n,j<m, a[i]<=a[n],b[j]<=b[m])
else dp[n][m] = max(dp[i][j])  ;(i<n,j<m)
这样的结果是,时间复杂度为O(n^4)

我们换一种思路,我们发现每次dp[i][j]的长度会增加1的情况都是a[i]==b[j],
所以我们定义dp[i][j]为以第一个字符的第i个字符结尾和第二个字符的前j个字符
组成的最长上升子序列,这样的递推结果为:
if(a[n]==b[m]) dp[n][m] = max(dp[n-1][j])+1 ;(j<m, b[j]<=b[m])
else dp[n][m] = dp[n-1][m] ;
此时时间复杂度为O(n^3)

5
1 4 2 5 -12
4
-12 1 2 4
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值