最長公共上升子序列[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;
    
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章