「暑期訓練」「基礎DP」 Common Subsequence (POJ-1458)

SamHX發表於2018-08-12

 

題意與分析

很簡單:求最長公共子序列。
注意子序列與子串的差別:一個不連續一個連續。一份比較好的參考資料見:https://segmentfault.com/a/1190000002641054

狀態轉移方程是這樣的:
dp[i][j]dp[i][j]為a串1~i、b串1~j中的最長的公共子序列,則

dp[i][j]={dp[i1][j1]+1,  max(dp[i1][j],dp[i][j1]),  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[i1][j1]+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;
}

相關文章