最长公共上升子序列[DP]

两个字符串a和b,需要统计出其中公共子序列的最长是多少。
注意:所谓子序列,指的是出现的先后顺序一样,但可以不连续出现。比如对于s=abdef,其中adf是s 的一个子序列,因为对于adf中每个字符,其出现的先后顺序与s中先后顺序一致。

这是一道DP题

状态表示

状态表示f(i,j) 表示 字符串a中(a1~ai)个字符与 字符串b中( b1 ~bj)个字符中公共子序列的最大值。

按照ai和bj是否相等来分,
如果相等,最后一位必然是相同的,
这样的话,也就是在a1~ai-1中选,和在b1 ~ bj-1中选,组成公共子序列的最大值,然后加1即可,即f(i-1,j-1)+1

如果最后一位不等,必然有一个多余

表示
01=不包含ai,但是包含bj
10=包含ai,但是不包含bj

对于01,也就是在a1~ai-1中选,和在b1 ~ bj中选,组成公共子序列的最大值,f(i-1,j)
对于10,也就是在a1~ai中选,和在b1 ~ bj-1中选,组成公共子序列的最大值,即f(i,j-1)

最后f(i,j) 就与三种状态有关 :f(i1,j1),f(i1,j),f(i,j1)f(i-1,j-1), f(i-1,j), f(i,j-1),

状态转移


f[i][j]=max(f[i-1][j],f[i][j-1]);//01和10状态必有,选择最大的
if(a[i]==b[j])  //
	f[i][j]=max(f[i][j],f[i-1][j-1]+1);

最后的答案
f[n][m],n是字符串a的长度,m是字符串b的长度

acwing ac代码

#include<iostream>
#include<string>
#include<cstring>

using namespace std;
const int maxn=1010;
char a[maxn],b[maxn];
int n,m;
int f[maxn][maxn];//f[i][j]表示a1-ai中和b1-bj中公共子序列的最长长度


int main(){
    memset(f,0,sizeof(f));
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];//读入
     for(int i=1;i<=m;i++) cin>>b[i];
     
    for(int i=1;i<=n;i++){//遍历a
        for(int j=1;j<=m;j++){//遍历b
            f[i][j]=max(f[i-1][j],f[i][j-1]);
            if(a[i]==b[j]) 
                f[i][j]=max(f[i][j],f[i-1][j-1]+1);
        }
    }
    cout<<f[n][m]<<endl;
    return 0;
    
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章