「暑期训练」「基础DP」 Common Subsequence (POJ-1458)

题意与分析

很简单:求最长公共子序列。
注意子序列与子串的差别:一个不连续一个连续。一份比较好的参考资料见: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;
}
如非注明,原创内容遵循GFDLv1.3发布;其中的代码遵循GPLv3发布。
原文地址:https://www.cnblogs.com/samhx/p/9652048.html