题目描述
一个给定序列的子序列是在该序列中删去若干元素后得到的序列。确切地说,若给定序列 X=<x1,x2,…,xm>,则另一序列 Z=<z1,z2,…,zk>是 X 的子序列是指存在一个严格递增的下标序列<i1,i2,…,ik>,使得对于所有j=1,2,…,k 有:Xij=Zj例如,序列 z=<B,C,D,B>是序列 X=<A,B,C,B,D,A,B>的子序列,相应的递增下标序列为<2,3,5,7>。给定两个序列 X 和 Y,当序列 Z 既是 X 的子序列又是 Y的子序列时,称 z 是序列 x 和 Y 的公共子序列。例如,若 x<A,B,C,B,D,A,B>和 Y=<B,D,C,A,B,A>,则序列<B,C,A>是 X 和 Y 的一个公共子序列,序列<B,C,B,A>是 X 和 Y 的一个公共子序列。而且,后者是 X 和 Y 的一个最长公共子序列.因为 X 和 Y 没有长度大于 4 的公共子序列。给定两个序列 X=<x1,x2,…,xm>和 Y=<y1,y2….yn>.要求找出 X 和 Y 的一个最长公共子序列。
输入格式
输入文件共有两行。每行为一个由大写字母构成的长度不超过 200 的字符 串,表示序列 X 和 Y。
输出格式
输出文件第一行为一个非负整数。表示所求得的最长公共子序列的长度。 若不存在公共子序列.则输出文件仅有一行输出一个整数 0。
输入样例
ABCBDAB
BDCABA
输出样例
4
首先想到的就是线性动规,最重要的就是找到动态转移方程。那么如何推出状态方程那么就是画图了,从图中可以更好的了解每个dp数组的变化。
b | B | D | C | A | B | A | |
a | dp | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
B | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
C | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
B | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
D | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
B | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
刚开始dp数组全部初始化为0,然后开始比较a和b的每个元素,首先看到b的第一个字符‘B’
当a出现‘B’后那么后边的dp数组就全部加一
b | B | D | C | A | B | A | |
a | dp | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
B | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
C | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
B | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
D | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
B | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
依此类推
因为看的是b所以计数是a数组
b | B | D | C | A | B | A | |
a | dp | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
B | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
C | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
B | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
D | 0 | 1 | 2 | 2 | 2 | 2 | 2 |
A | 0 | 1 | 2 | 0 | 0 | 0 | 0 |
B | 0 | 1 | 2 | 0 | 0 | 0 | 0 |
b | B | D | C | A | B | A | |
a | dp | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
B | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
C | 0 | 1 | 1 | 2 | 2 | 2 | 2 |
B | 0 | 1 | 1 | 2 | 2 | 2 | 2 |
D | 0 | 1 | 2 | 2 | 2 | 2 | 2 |
A | 0 | 1 | 2 | 3 | 3 | 3 | 3 |
B | 0 | 1 | 2 | 3 | 4 | 4 | 4 |
有很多人应该看不懂画的意思,其实就是当遇到相同的数字后,那么就让这个dp数组在a和b的上一个dp上加一(dp[i - 1][j - 1] + 1),假如不同的话就从它的上一个字母找出最大的数字,将值赋给它及(max(dp[i - 1][j], dp[i][j - 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;
}else
{
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
代码如下:
#include<bits/stdc++.h>
using namespace std;
int dp[205][205];
int main()
{
string a, b;
cin >> a >> b;
a = '0' + a;
b = '0' + b;
int len1 = a.size();
int len2 = b.size();
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;
}else
{
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
cout << dp[len1 - 1][len2 - 1] << endl;
return 0;
}
为什么要加字符‘0’呢,就是为了让第一个字符可以得到计算,如果没有那么假如第一个字符相同那么就会出错。