P2516 [HAOI2010]最长公共子序列 题解(LCS)

题目链接

最长公共子序列

解题思路

第一思路:

1.用\(length[i][j]\)表示\(a\)串的前\(i\)个字符与\(b\)串的前\(j\)个字符重叠的最长子串长度

2.用\(num[i][j]\)表示 \(a\)串的前\(i\)个字符与\(b\)串的前\(j\)个字符重叠的最长子串个数

则求\(length[i][j],num[i][j]\)时有以下递推关系:

\(length[i][j]:\)

如果当前两串结尾字符相等,则\(length[i][j]=length[i-1][j-1]+1\)

否则\(length[i][j]=max(length[i-1][j],length[i][j-1])\)

\(num[i][j]:\)

如果\(length[i][j]\)与\(length[i-1][j]\)相等,\(num[i][j]\)可加\(num[i-1][j]\)

如果\(length[i][j]\)与\(length[i][j-1]\)相等,\(num[i][j]\)可加\(num[i][j-1]\)

如果\(length[i][j]\)与\(length[i-1][j-1]\)相等,则\(num[i][j]\)多加了个\(num[i-1][j-1]\),需要减去

代码:

#include<stdio.h>
#include<string.h>
#define max(a,b) (a>b?a:b)
int length[5010][5010],num[5010][5010],w=100000000;
char a[5010],b[5010];
int main(){
    int i,j,la,lb;
    scanf("%s%s",a,b);
    la=strlen(a)-1;lb=strlen(b)-1;
    for(i=0;i<=la;i++)num[i][0]=1;
    for(i=0;i<=lb;i++)num[0][i]=1;
    for(i=1;i<=la;i++){
        for(j=1;j<=lb;j++){
            if(a[i-1]==b[j-1]){
                length[i][j]=length[i-1][j-1]+1;
                num[i][j]=num[i-1][j-1];
            }
            else{
                length[i][j]=max(length[i-1][j],length[i][j-1]);
                if(length[i][j]==length[i-1][j-1])num[i][j]-=num[i-1][j-1];
                num[i][j]+=w;
            }
            if(length[i-1][j]==length[i][j])num[i][j]+=num[i-1][j];
            if(length[i][j-1]==length[i][j])num[i][j]+=num[i][j-1];
            num[i][j]%=w;
            length[i][j]%=w;
        }
    }
    printf("%d\n%d",length[la][lb],num[la][lb]);
    return 0;
}

提交效果

优化代码

考虑优化代码。

考虑到\(length\)、\(num\)数组当前状态都只与上一状态相关,可以用滚动数组优化空间和时间。

AC代码

#include<stdio.h>
#include<string.h>
#define max(a,b) (a>b?a:b)
int length[2][5010],num[2][5010],w=100000000;
char a[5010],b[5010];
int main(){
    int i,j,la,lb;
    scanf("%s%s",a,b);
    la=strlen(a)-1;lb=strlen(b)-1;
    for(i=0;i<=lb;i++)num[0][i]=1;
    num[1][0]=1;
    for(i=1;i<=la;i++){
        int temp=i%2;
        for(j=1;j<=lb;j++){
            num[temp][j]=0;//滚动数组一定要注意这一点
            if(a[i-1]==b[j-1]){
                length[temp][j]=length[temp^1][j-1]+1;
                num[temp][j]=num[temp^1][j-1];
            }
            else{
                length[temp][j]=max(length[temp^1][j],length[temp][j-1]);
                if(length[temp][j]==length[temp^1][j-1])num[temp][j]-=num[temp^1][j-1];
                num[temp][j]+=w;
            }
            if(length[temp^1][j]==length[temp][j])num[temp][j]+=num[temp^1][j];
            if(length[temp][j-1]==length[temp][j])num[temp][j]+=num[temp][j-1];
            num[temp][j]%=w;
            length[temp][j]%=w;
        }
    }
    printf("%d\n%d",length[la%2][lb],num[la%2][lb]);
    return 0;
}

提交效果

原文地址:https://www.cnblogs.com/Potassium/p/9989173.html

时间: 2024-08-01 15:30:46

P2516 [HAOI2010]最长公共子序列 题解(LCS)的相关文章

[HAOI2010]最长公共子序列

[问题描述] 字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列x="x0,x1,-,xn-1", 序列Y="y0,y1,-,yk-1是X的子序列,存在X的一个严格递增下标序 列<i0,i1,-,ik-1>,使得对所有的j=0,1,-,k- 1,有xij="yj. 例如,x="ABCBDAB",Y="BCDB"是X的一个子序列. 对给定的两

最长公共子序列(LCS)、最长递增子序列(LIS)、最长递增公共子序列(LICS)

最长公共子序列(LCS) [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列<i0,i1,…,ik-1>,使得对所有的j=0,1,…,k-1,有xij=yj.例如,X=“ABCBDAB”,Y=“BCDB”是X的一个子序列. 考虑最长公共子序列问题如何分解成

最长公共子序列问题 (LCS)

给定两个字符串S和T.求出这两个字符串最长的公共子序列的长度. 输入: n=4 m=4 s="abcd" t="becd" 输出: 3("bcd") 这类问题被称为最长公共子序列问题(LCS,Longest Common Subsequence)的著名问题. max(dp[i][j]+1,dp[i][j+1],dp[i+1][j])   (s=t) dp[i+1][j+1]= max(dp[i][j+1],dp[i+1][j])        

最长公共子序列问题LCS

题目: 链接:点击打开链接 题意: n个课程m天完成,a[i][j]表示用j天完成第i个课程得到的价值,求最大价值. 算法: 分组背包. 思路: m天是总容量,n是组数. 代码: #include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,m; int a[110][110]; int dp[110]; int main() { //freopen("inpu

[BZOJ 2423] [HAOI2010] 最长公共子序列

2423: [HAOI2010]最长公共子序列 Time Limit: 10 SecMemory Limit: 128 MB Description 字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列<i0,i1,…,ik-1>,使得对所有的j=0,1,…,k-1,有xij = yj.例如,X=“ABCBDA

动态规划——最长公共子序列(LCS)

最长公共子序列的问题描述为: 下面介绍动态规划的做法. 令 dp[i][j] 表示字符串 A 的 i 号位与字符串 B 的 j 号位之前的 LCS 长度(下标从 1 开始),如 dp[4][5] 表示 "sads" 与 "admin" 的 LCS 长度.那么可以根据 A[i] 和 B[j] 的情况,分为两种决策: 若 A[i]==B[j],则字符串 A 与字符串 B 的 LCS 增加了 1 位,即有 dp[i][j]=dp[i-1][j-1]+1. 若 A[i] !

动态规划法(十)最长公共子序列(LCS)问题

问题介绍 ??给定一个序列\(X=<x_1,x_2,....,x_m>\),另一个序列\(Z=<z_1,z_2,....,z_k>\)满足如下条件时称为X的子序列:存在一个严格递增的X的下标序列\(<i_1,i_2,...,i_k>\),对所有的\(j=1,2,...,k\)满足\(x_{i_j}=z_j.\) ??给定两个序列\(X\)和\(Y\),如果\(Z\)同时是\(X\)和\(Y\)的子序列,则称\(Z\)是\(X\)和\(Y\)的公共子序列.最长公共子序列(

最长公共子序列(LCS)问题

最长公共子串(Longest Common Substirng)和最长公共子序列(Longest Common Subsequence,LCS)的区别为:子串是串的一个连续的部分,子序列则是从不改变序列的顺序,而从序列中去掉任意的元素而获得新的序列:也就是说,子串中字符的位置必须是连续的,子序列则可以不必连续. 1.序列str1和序列str2 ·长度分别为m和n: ·创建1个二维数组L[m.n]: ·初始化L数组内容为0 ·m和n分别从0开始,m++,n++循环: - 如果str1[m] ==

[BZOJ2423][HAOI2010]最长公共子序列

试题描述 字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列<i0,i1,…,ik-1>,使得对所有的j=0,1,…,k-1,有xij = yj.例如,X=“ABCBDAB”,Y=“BCDB”是X的一个子序列.对给定的两个字符序列,求出他们最长的公共子序列长度,以及最长公共子序列个数. 输入 第1行为第1个字