hdu1423 Greatest Common Increasing Subsequence

题意:求最长公共上升子序列的长度。

思路:结合了LCS,LIS两个算法的思想,最初我自己思路是根据:LCS很容易想到定义 dp[i][j] 表示第一格串前i个和第二个串的前j个最长公共上升子序列的长度,

首先根据最长公共子序列思想,如果a[i]=b[j],,就在b[1]到b[j-1]前面选一个dp[i][k],满足b[j]>b[k]&&dp[i][k]是最大的,为什么呢?你想,如果某一个时刻a[i]==b[j],那么显然,我们就应该在0到j-1中,找一个dp值最大的来更新最优解,这和最长上升子序列想法是一样的。如果a[i]!=b[j],dp[i][j]=max(dp[i-1][j],dp[i][j-1]).

代码如下:

缺点是这样写,时间复杂度是n^3.

#include<bits/stdc++.h>
using namespace std;
int a[700],b[700],dp[700][700];
const int inf=0x7fffffff;
int main()
{
    int T,ok=0;cin>>T;
    while(T--){
        a[0]=b[0]=-inf;
        int n,m;cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        cin>>m;
        for(int i=1;i<=m;i++) cin>>b[i];
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
               if(a[i]==b[j]){
                   if(j==1) dp[i][j]=1;
                   for(int k=1;k<j;k++){//寻找满足条件的最大k
                     if(b[j]>b[k])
                     dp[i][j]=max(dp[i][j],dp[i][k]+1);
                   }
               }
               else{
                 dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
               }
            }
        }
        if(!ok) ok=1;
        else cout<<endl;
        cout<<dp[n][m]<<endl;
    }
}

上面这个代码,这里当a[i]==b[j],查找最大的k,需要0(n)。但实际上,k并不需要扫一遍,当a[i]!=b[j]的时候就可以保存dp[i][j]中最大的那个一个也就是dp[i][k].解化过的算法时间复杂度是n^2.

zh#include<bits/stdc++.h>
using namespace std;
int a[700],b[700],dp[700][700];
const int inf=0x7fffffff;
int main()
{
    int T,ok=0;cin>>T;
    while(T--){
        a[0]=b[0]=-inf;
        int n,m;cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        cin>>m;
        for(int i=1;i<=m;i++) cin>>b[i];
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            int k=1;
            for(int j=1;j<=m;j++){
               if(a[i]==b[j]){
                   if(j==1) dp[i][j]=1;
                   if(b[j]>b[k]) dp[i][j]=dp[i][k]+1;
               }
               else{
                  dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
                  if(dp[i][j]>dp[i][k]) k=j;
               }
            }
        }

        if(!ok) ok=1;
        else cout<<endl;
        cout<<dp[n][m]<<endl;
    }
}
还有一种思路是:节省一维的空间,定义dp[i]为以b中第i个位置结尾的子串和a的最长公共上升子序列的长度,然后看代码吧,思路和上面的差不多.....

#include<bits/stdc++.h>
using namespace std;
int dp[1100],a[1100],b[1100],k;
int main()
{
    int T,ans,ok=0;cin>>T;
    while(T--){
        int n,m;
        cin>>n; for(int i=1;i<=n;i++) cin>>a[i];
        cin>>m; for(int i=1;i<=m;i++) cin>>b[i];
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            k=1;
            for(int j=1;j<=m;j++){
                if(a[i]==b[j]){
                   dp[j]=max(dp[j],dp[k]+1);
                }
                if(a[i]>b[j]){
                   if(dp[k]<dp[j]) k=j;
                }
            }
        }
        if(!ok) ok=1;
        else cout<<endl;
        ans=0;
        cout<<*max_element(dp+1,dp+m)<<endl;
    }
}





你可能感兴趣的:(hdu1423 Greatest Common Increasing Subsequence)