前段时间我写过最长递增子序列,我们用到的是动态规划的思想,今天谈的最长公共子序列仍然是动态规划的一个十分重要的一部分。结合算法导论的讲解,谈谈我自己的理解。求解的关键是描述的过程,先引进一个定理:
(lcs最优子结构)设x=(x1,x2,……,xm)和y=(y1,y2,……,yn)为两个序列,并设z=(z1,z2……,zk)为x和y的任意一个lcs.
1)如果xm=yn,那么zk=xm=yn而且zk-1是xm-1和yn-1的一个lcs;
2)如果xm!=yn,那么zk!=xm蕴含z是xm-1和y的一个lcs;
3)如果xm!=yn,那么zk!=yn蕴含z是x和yn-1的一个lcs;
关于证明的过程,我就滤过了,那么关键是我们知道了这个定理,我们就应该遵循动态规划的第二个步骤了,找递归解,根据定理,我们很容易的找到了递归解,既:
c[i][j]= 1) 0 如果i=0,j=0;
2)c[i-1][j-1]+1 如果i>0,j>0和xi=yj
3)max(c[i][j-1],c[i-1][j]) 如果i,j>0和xi!=yj
从而剩下的就是写代码了,代码是自己写的,如果有哪些不对的地方,欢迎拍砖!!!
C语言:
Codee#13001
//******************************************************
//题目:最长公共子序列
//by dashan1990
//完成时间:2010,8
//完成状态:已完成。
//*******************************************************
#include <stdio.h>
#include <string.h>
#define MAX 100
int a [ MAX ],b [ MAX ];
int c [ MAX ][ MAX ];
int n , m;
int LCS_lenght()
{
int i , j;
for( i = 0; i <n; i ++)
{
c [ i ][ 0 ] = 0;
c [ 0 ][ i ] = 0;
}
for( i = 0; i <n; i ++)
{
for( j = 0; j < m; j ++)
{
if( a [ i ] ==b [ j ])
{
c [ i ][ j ] = c [ i - 1 ][ j - 1 ] + 1;
}
else if( c [ i - 1 ][ j ] >= c [ i ][ j - 1 ] && a [ i ] !=b [ j ])
{
c [ i ][ j ] = c [ i - 1 ][ j ];
}
else if( a [ i ] !=b [ j ] && c [ i - 1 ][ j ] < c [ i ][ j - 1 ])
{
c [ i ][ j ] = c [ i ][ j - 1 ];
}
}
}
return c [n - 1 ][ m - 1 ];
}
int main()
{
int i , j;
int w;
while( scanf( "%d%d" , &n , & m))
{
for( i = 0; i <n; i ++)
{
scanf( "%d" , a + i);
}
for( i = 0; i < m; i ++)
{
scanf( "%d" , &b [ i ]);
}
w = LCS_lenght();
printf( "%d" , w);
putchar( '/n');
}
return 0;
}
//题目:最长公共子序列
//by dashan1990
//完成时间:2010,8
//完成状态:已完成。
//*******************************************************
#include <stdio.h>
#include <string.h>
#define MAX 100
int a [ MAX ],b [ MAX ];
int c [ MAX ][ MAX ];
int n , m;
int LCS_lenght()
{
int i , j;
for( i = 0; i <n; i ++)
{
c [ i ][ 0 ] = 0;
c [ 0 ][ i ] = 0;
}
for( i = 0; i <n; i ++)
{
for( j = 0; j < m; j ++)
{
if( a [ i ] ==b [ j ])
{
c [ i ][ j ] = c [ i - 1 ][ j - 1 ] + 1;
}
else if( c [ i - 1 ][ j ] >= c [ i ][ j - 1 ] && a [ i ] !=b [ j ])
{
c [ i ][ j ] = c [ i - 1 ][ j ];
}
else if( a [ i ] !=b [ j ] && c [ i - 1 ][ j ] < c [ i ][ j - 1 ])
{
c [ i ][ j ] = c [ i ][ j - 1 ];
}
}
}
return c [n - 1 ][ m - 1 ];
}
int main()
{
int i , j;
int w;
while( scanf( "%d%d" , &n , & m))
{
for( i = 0; i <n; i ++)
{
scanf( "%d" , a + i);
}
for( i = 0; i < m; i ++)
{
scanf( "%d" , &b [ i ]);
}
w = LCS_lenght();
printf( "%d" , w);
putchar( '/n');
}
return 0;
}