2018.11.2 2018NOIP衝刺之最短公共父串
阿新 • • 發佈:2018-11-02
很有意思的一個題
試題描述 |
給定字串A和字串B,要求找一個最短的字串,使得字串A和B均是它的子序列。 |
輸入 |
輸入包含兩行,每行一個字串,分別表示字串A和字串B。(串的長度不超過30) |
輸出 |
輸出A和B最短公共父串的長度以及在該長度下可以生成的父串個數,用空格隔開。 |
輸入示例 |
ABAAXGF AABXFGA |
輸出示例 |
10 9 |
其他說明 |
ABAAXGF和AABXFGA的最短公共父串之一是AABAAXGFGA,長度為10,滿足該長度的父串一共有9個。 |
看到這個題有沒有想到最長公共子序列??這個題情況類似
我們用dp[i][j]表示第一個串前i位以及第二個串前j位最短公共父串的長度,用f[i][j]同理表示有幾個最短公共父串
不難得到
當a[i]==b[j]時 dp[i][j]=dp[i-1][j-1]+1
否則dp[i][j]=min(dp[i-1][j],dp[i][j-1])+1(參見最長公共子序列)
同樣的
當a[i]==b[j]時說明串的個數應該從f[i-1][j-1]的位置轉移 於是f[i][j]=f[i-1][j-1]
否則:
(1)當dp[i-1][j]<dp[i][j-1]時說明從f[i-1][j]轉移的父串最短 於是f[i][j]=f[i-1][j]
(2)當dp[i][j-1]<dp[i-1][j]時說明從f[i][j-1]轉移的父串最短 於是f[i][j]=f[i][j-1]
(3)當dp[i-1][j]==dp[i][j-1]時說明兩邊轉移的父串都是最短 於是f[i][j]=f[i-1][j]+f[i][j-1]
上程式碼
#include<iostream> #include<cstring> using namespace std; int dp[105][105],f[105][105],len1,len2,cnt; char a[105],b[105]; int main() { gets(a+1),gets(b+1); len1=strlen(a+1),len2=strlen(b+1); for(int i=0;i<=max(len1,len2);i++)dp[i][0]=dp[0][i]=i; for(int i=0;i<=max(len1,len2);i++)f[i][0]=f[0][i]=1; for(int i=1;i<=len1;i++) { for(int j=1;j<=len2;j++) { if(a[i]==b[j]) { dp[i][j]=dp[i-1][j-1]+1; f[i][j]=f[i-1][j-1]; } else { dp[i][j]=min(dp[i-1][j],dp[i][j-1])+1; if(dp[i-1][j]<dp[i][j-1])f[i][j]=f[i-1][j]; else if(dp[i][j-1]<dp[i-1][j])f[i][j]=f[i][j-1]; else f[i][j]=f[i-1][j]+f[i][j-1]; } } } printf("%d %d",dp[len1][len2],f[len1][len2]); }