LCS LIS LCIS 算法

           (这么久了,才开始写题解,我也是够懒)
先是LCS(最长公共子序列),例题么(COGS 476,我知道这个很水),先来划分阶段:A中前i个字符,B中前J个字符。然后是状态:定义:f[i][j]为A中前i个字符和B中前J个字符的最长公共子序列。那么只有两种状态:相同&不同。决策:若相同则f[i][j]=f[i-1][j-1]+1;若不同则从I或j中去一个求最大值f[i][j]=max(f[i][j-1],f[i-1][j]);(动归三步走)
for(int i=1;i<=l1;i++){//l1 l2 分别为两个字符串长度
            for(int j=1;j<=l2;j++){
                if(s1[i]==s2[j])f[i][j]=f[i-1][j-1]+1;
                else f[i][j]=max(f[i-1][j],f[i][j-1]);
                ans=max(ans,f[i][j]);
            }
        }
然后是LIS(最长上升子序列):
n^2算法:对于下标i,A中前i位的最长上升子序列长度为以i之前下标为结尾的最长上升子序列的最大值当然结尾点的位置储存的数应当比i处储存的数要小。

小技巧:可以一边读入一遍计算;

for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        f[i]=1;//f[i]是到下标i最长上升子序列的长度;
        for(int j=1;j<i;j++){
            if(a[j]<a[i])f[i]=max(f[j]+1,f[i]);
        }
        ans=max(ans,f[i]);//保存最大解;
    }

nlogn算法:
保存最长上升子序列每一位上的最小值,那么对于以后的数,若对于一个数x,他比len位上的数大说明他可以构成一个长度为len+1长的上升序列,在此期间不断维护每一位上的数是这一位上的最小值,因满足单调性故查找时可以使用二分优化。

len=1;c[len]=a[1];
    for(int i=2;i<=n;++i){
        if(a[i]>c[len]) c[++len]=a[i];
        else{
            l=1,r=len;
            while(l<=r){
                int mid=(l+r)>>1;
                if(c[mid]<a[i]) l=mid+1;
                else r=mid-1;
            }
            c[l]=a[i];
        }
   }

LCIS(最长公共上升子序列):
例题:cogs 1669 神秘的咒语;
与LIS大致相同但是LCIS只有当两个字符串中某位置和某位置相等时才去查找之前的。

    for(int i=1;i<=n;i++){
            ans=0;
            for(int j=1;j<=m;j++){
                f[i][j]=f[i-1][j];
                if(num1[i]==num2[j])f[i][j]=ans+1;
                if(num1[i]>num2[j]&&ans<f[i-1][j])ans=f[i-1][j];
            }
        }

只敲一些片段可能看不懂,那就结合例题喽:
COGS 476:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
char s1[5005],s2[5005];
int f[5005][5005],l1,l2,ans;
int main(){
    //freopen("lcslength.in","r",stdin);
    //freopen("lcslength.out","w",stdout);
        scanf("%s%s",s1+1,s2+1);
        l1=strlen(s1+1)-1,l2=strlen(s2+1)-1,ans=0;
        for(int i=1;i<=l1;i++){
            for(int j=1;j<=l2;j++){
                if(s1[i]==s2[j])f[i][j]=f[i-1][j-1]+1;
                else f[i][j]=max(f[i-1][j],f[i][j-1]);
                ans=max(ans,f[i][j]);
            }
        }
        printf("%d\n",ans);
    return 0;
} 

COGS 1398:
n^2:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int a[1001],f[1001];
int main(){
    //freopen("lis1.in","r",stdin);
    //freopen("lis1.out","w",stdout);
    int n,ans=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        f[i]=1;
        for(int j=1;j<i;j++){
            if(a[j]<a[i])f[i]=max(f[j]+1,f[i]);
        }
        ans=max(ans,f[i]);
    }
    printf("%d",ans);
    return 0;
} 

nlogn:

#include<cstdio>
using namespace std;
int n,len,a[1005],c[1005],l,r;
inline void get1(int &x)
{
    char ch;
    while(ch=getchar(),ch<48||ch>57);
    x=ch-48;
    while(ch=getchar(),ch>47&&ch<58)x=x*10+ch-48;
}
int main(){
    freopen("lis1.in","r",stdin);
    freopen("lis1.out","w",stdout);
    get1(n);
    for(int i=1;i<=n;++i) get1(a[i]);
    len=1;c[len]=a[1];
    for(int i=2;i<=n;++i){
        if(a[i]>c[len]) c[++len]=a[i];
        else{
            l=1,r=len;
            while(l<=r){
                int mid=(l+r)>>1;
                if(c[mid]<a[i]) l=mid+1;
                else r=mid-1;
            }
            c[l]=a[i];
        }
   }
   printf("%d",len);
   return 0;
} 
//7

//1 7 3 5 9 4 8

COGS 1669:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int num1[505],num2[505],n,m,t,f[505][505],ans;
int main(){
    freopen("codes.in","r",stdin);
    freopen("codes.out","w",stdout);
    scanf("%d",&t);
    while(t--){
        memset(num1,0,sizeof(num1));
        memset(num2,0,sizeof(num2));
        memset(f,0,sizeof(f));
        ans=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&num1[i]);
        scanf("%d",&m);
        for(int i=1;i<=m;i++)scanf("%d",&num2[i]);
        for(int i=1;i<=n;i++){
            ans=0;
            for(int j=1;j<=m;j++){
                f[i][j]=f[i-1][j];
                if(num1[i]==num2[j])f[i][j]=ans+1;
                if(num1[i]>num2[j]&&ans<f[i-1][j])ans=f[i-1][j];
            }
        }
        ans=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                ans=max(ans,f[i][j]);
            }
        }
        printf("%d",ans);
        if(t)printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值