| |||||
| |||||
|
这是一道经典而又基础的区间动规题目。
看到题目,我们可以轻易的想到,如果A串的前i个与B串的前j个元素的最长公共子序列长度为x,又如果A[i+1]=B[j+1],那么A串的前i+1个与B串的前j+1个元素的最长公共子序列长度就为x+1;
那么状态转移方程的一部分就显而易见了 f(i,j)=f(i-1,j-1)+1 (A[i]=B[j])
那么如果A[i]!=B[i]的时候呢?我们想想,如果A串的前i-1个与B串的前j个元素的最长公共子序列长度为x,那么A串的前i个与B串的前j个元素的最长公共子序列长度至少都有x;如果A串的前i个与B串的前j-1个元素的最长公共子序列长度为y,那么A串的前i个与B串的前j个元素的最长公共子序列长度至少都有y
那么剩下一部的状态转移方程就出来了 f(i,j)=MAX{ f(i-1,j) , f(i,j-1) } (A[i]!=B[j])
有人会问,会不会f(i-1,j)或者f(i,j-1)比f(i-1,j-1)+1还大呢,这样在A[i]=B[j]时选择第二种方案岂不是更好?
这样的情况是不存在的,因为f(i-1,j)或者f(i,j-1)只会比f(i-1,j-1)大1个长度(想想为什么),所以f(i-1,j)或者f(i,j-1)不会比f(i-1,j-1)+1还大
边界 f(0,0)=0
f(0,j)=0
f(i,0)=0
最后答案:f(a,b);(a表示A的长度,b表示B的长度)
程序:
#include<iostream>
#include<cstdio>
#include<cstring>
#define f(i,j) d[(i)-1][(j)-1]
using namespace std;
char A[205],B[205];
int d[205][205];
void Ready()
{
scanf("%s",A);
scanf("%s",B);
memset(d,0,sizeof(d));
}
int MAX(int x,int y)
{
return x>y?x:y;
}
void Working()
{
int a,b;
a=strlen(A);
b=strlen(B);
if(A[0]==B[0])f(1,1)=1;
for(int i=2;i<=a;i++)
{
f(i,1)=f(i-1,1);
if(A[i-1]==B[0])f(i,1)=1;
}
for(int i=2;i<=b;i++)
{
f(1,i)=f(1,i-1);
if(A[0]==B[i-1])f(1,i)=1;
}
for(int i=2;i<=a;i++)
for(int j=2;j<=b;j++)
{
f(i,j)=MAX(f(i-1,j),f(i,j-1));
if(A[i-1]==B[j-1])
f(i,j)=MAX(f(i,j),f(i-1,j-1)+1);
}
printf("%d",f(a,b));
}
int main()
{
Ready();
Working();
return 0;
}