子序列

本文深入探讨了动态规划中的关键算法,包括最长公共子序列(LCS)、最长严格递增子序列(LIS)、最长公共上升子序列(LCIS)等,详细讲解了状态转移方程及其实现过程。此外,还介绍了最大连续子序列和最大m字段的求解方法,为读者提供了丰富的算法案例和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LCS ( O(n*m) )

最长公共子序列

dp[i][j]表示a数组前i个,b数组前j个的最长公共子序列长度

状态转移方程:

a[i]!=b[j]

dp[i][j]=max(dp[i-1][j],dp[i][j-1]);

a[i]==b[j]

dp[i][j]=dp[i-1][j-1]+1;

for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        if(a[i]==b[j])
        dp[i][j]=dp[i-1][j-1]+1;
    else
        dp[i][j]=max(dp[i-1][j],dp[i][j-1]);

 

 

LIS ( O(nlogn )

最长严格递增子序列

 

//lower_bound(begin,end,num)在从小到大的数组中,返回第一个大于等于num的数的地址
        fill(lis,lis+110,INT_MAX);
        for(int i=0;i<n;i++)
            {
                cin>>x;
                *lower_bound(lis,lis+110,x)=x;
            }
            cout<<lower_bound(lis,lis+110,INT_MAX)-lis<<endl;
打印路径:当在lis中填入x时,前一位一定是小于且先于x的,那么pre[x]=lis[x的位置-1]

LCIS ( O(n*m)

最长公共上升子序列

 

a[]={1,4,2,5,-12}
b[]={-12,1,2,4} 

dp[i][j]表示 a的前i个和b的前j个数,以b[j]为结尾 的lcis

状态转移方程:

当a[i]!=b[j],
a的前i个和b的前j个数,以b[j]为结尾的lcis=a的前i-1个和b的前j个数,以b[j]为结尾的lcis
① a[i] != b[j], dp[i][j] = dp[i-1][j]

当a[i]==b[j],
a的前i个和b的前j个数,以b[j]为结尾的lcis=a的前i-1个和b的前k个数(1<=k<j,dp[i-1][k]最大且b[k]<b[j]),以b[k]为结尾的lcis

② a[i] == b[j], dp[i][j] = max(dp[i-1][k]+1) (1 <= k < j && b[j] > b[k])


 

 memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
        {
            int max_=0;
            for(int j=1;j<=m;j++)
            {
                if(a[i]!=b[j])
                    dp[i][j]=dp[i-1][j];
                else
                    dp[i][j]=max_+1;
                if(a[i]>b[j])
                    max_=max(max_,dp[i][j]);
            }
        }

最大连续子序列

int head=0,rehead=0,rear=0,maxn=-1,res=0;
        for(int i=0;i<n;i++)
        {
            res+=a[i];//res为当前的连续子序列和
            if(res<0) //不可能是最终答案
            {
                res=0;
                rehead=i+1;
            }
            else
            {
                if(maxn<res)//可能是最终答案,更新数据
                {
                    maxn=res;
                    head=rehead;//rebegin为最近一次更新的起始端
                    rear=i;
                }
            }
        }
\\前缀和
#include <bits/stdc++.h>

using namespace std;
int a[100010],sum[100010];
const int INF=0x3f3f3f;
int main()
{
    int t,n;
    scanf("%d",&t);
    for(int k=1;k<=t;k++)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
                sum[i]=sum[i-1]+a[i];
            }
        int min_val=INF,ans=-INF,l,rl,r;
        for(int i=1;i<=n;i++)
        {
            if(min_val>sum[i-1])
            {
                min_val=sum[i-1];
                rl=i;
            }
            if(ans<sum[i]-min_val)
            {
                ans=sum[i]-min_val;
                l=rl,r=i;
            }
        }
        printf("Case %d:\n%d %d %d\n",k,ans,l,r);
        if(k<t) putchar('\n');
    }
    return 0;
}

最大m字段

数组a[]={-4,5,6,-2,3,1}

dp[i][j]表示将 数组前j个数分成i段,并且最后一段以第j个数结尾 的最大和

状态转移方程:

拼接a[j]到第i段末尾

dp[i][j]=dp[i][j-1]+a[j];

a[j]单独作为第i段开头

dp[i][j]=dp[i-1][k]+a[j],     i-1<=k<j;

memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
        {
            int max_=dp[i-1][i-1];
            dp[i][i]=dp[i-1][i-1]+a[i];
            for(int j=i+1;j<=n;j++)
            {
                max_=max(max_,dp[i-1][j-1]);
                dp[i][j]=max(max_,dp[i][j-1])+a[j];
            }
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值