LCS長度個數計算

子串

給定一個字符串 A1..n

對於任意一個集合 G1..m 並且 1G1<G2<<Gmn

那麼 AG1..m 就是 A 的一個子串

如:

AABC 就是ABCABC的一個子串

LCS

給定兩個字符串 A,B ,求出他們最長的公共子串 C

意思是: C 既是 A 的子串,又是 B 的子串

求法

先給出代碼:

#define mod 1000000007
#define N 5010
int n,m,f[N][N],h[N][N],ans;
char s1[N],s2[N];
int main()
{
    scanf("%s%s",s1+1,s2+1);
    n=strlen(s1+1);
    m=strlen(s2+1);
    fr(i,1,n)
        f[i][0]=1;
    fr(i,0,m)
        f[0][i]=1;
    fr(i,1,n)
        s1[i]-='a'-1;
    fr(i,1,m)
        s2[i]-='a'-1;
    fr(i,1,n)
        fr(j,1,m)
            if(s1[i]==s2[j])
            {
                h[i][j]=h[i-1][j-1]+1;
                f[i][j]=f[i-1][j-1];
                if(h[i-1][j]==h[i][j])
                    f[i][j]=(f[i][j]+f[i-1][j])%mod;
                if(h[i][j-1]==h[i][j])
                    f[i][j]=(f[i][j]+f[i][j-1])%mod;
            }
            else
            {
                h[i][j]=max(h[i-1][j],h[i][j-1]);   
                if(h[i-1][j]==h[i][j])
                    f[i][j]=(f[i][j]+f[i-1][j])%mod;
                if(h[i][j-1]==h[i][j])
                    f[i][j]=(f[i][j]+f[i][j-1])%mod;
                if(h[i-1][j-1]==h[i][j])
                    f[i][j]=(f[i][j]-f[i-1][j-1]+mod)%mod;
            }
    printf("%d\n%d\n",h[n][m],f[n][m]);
    return 0;
}

hn,m 表示LCS長度

fn,m 表示LCS個數

我們可以得出

hi,j=hi1,j1+1max{hi1,jhi,j1s1i=s2js1is2j

fi,j 有些複雜,需要考慮許多情況:

我們先設一個函數 p(...)={10...true...false

fi,j={fi1,j1+p(hi1,j=hi,j)×fi1,j+p(hi,j1=hi,j)×fi,j1p(hi1,j=hi,j)×fi1,j+p(hi,j1=hi,j)×fi,j1p(hi1,j1=hi,j)×fi1,j1s1i=s2js1is2j

反正我是覺得沒看代碼直觀。

至於這些怎麼推出來的,應該是隻有最後一條有疑問,反正減就是去重,可以參考NOIP2016Day2T1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章