題意與分析
很簡單:求最長公共子序列。
注意子序列與子串的差別:一個不連續一個連續。一份比較好的參考資料見:https://segmentfault.com/a/1190000002641054
狀態轉移方程是這樣的:
設dp[i][j]dp[i][j]為a串1~i、b串1~j中的最長的公共子序列,則
dp[i][j]={dp[i−1][j−1]+1, max(dp[i−1][j],dp[i][j−1]), a[i]=b[j],a[i]≠b[j]dp[i][j]={dp[i−1][j−1]+1, a[i]=b[j],max(dp[i−1][j],dp[i][j−1]), a[i]≠b[j]
類似地,最長公共子串是這樣求的:
定義dp[i][j]dp[i][j]為以i、j為末尾的最長子串,有
dp[i][j]={dp[i−1][j−1]+1, 0, a[i]=b[j],a[i]≠b[j]dp[i][j]={dp[i−1][j−1]+1, a[i]=b[j],0, a[i]≠b[j]
稍微不同地,多個字串的公共子串/子序列求法如下:
https://blog.csdn.net/luxiaoxun/article/details/7915962
https://blog.csdn.net/liang5630/article/details/8095404
以後補題/訓練的時候再仔細探討。
程式碼
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#define MP make_pair
#define PB push_back
#define fi first
#define se second
#define ZERO(x) memset((x), 0, sizeof(x))
#define ALL(x) (x).begin(),(x).end()
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define per(i, a, b) for (int i = (a); i >= (b); --i)
#define QUICKIO \
ios::sync_with_stdio(false); \
cin.tie(0); \
cout.tie(0);
using namespace std;
template<typename T>
T read()
{
T tmp; cin>>tmp;
return tmp;
}
int dp[1005][1005];
string a,b;
int solve(int i,int j)
{
if(i<0 || j<0) return 0;
if(dp[i][j]!=-1)
return dp[i][j];
if(a[i]==b[j])
{
return dp[i][j]=solve(i-1,j-1)+1;
}
else
{
return dp[i][j]=max(solve(i-1,j),solve(i,j-1));
}
}
int main()
{
QUICKIO
while(cin>>a>>b)
{
memset(dp,-1,sizeof(dp));
cout<<solve(a.size()-1,b.size()-1)<<endl;
}
return 0;
}