题目链接:http://poj.org/problem?id=1458
思路分析:经典的最长公共子序列问题(longest-common-subsequence proble),使用动态规划解题。
1)问题定义:给定两个序列X=<X1, X2, ...., Xm>和Y = <Y1, Y2, ...., Yn>,要求求出X和Y长度最长的最长公共子序列;
2)问题分析:
<1>动态规划问题都是多阶段决策最优化问题;在这些问题中,问题可以被划分为多个阶段,每个阶段都需要作出一个决策,在问题的多阶段决策中,
按某一顺序,根据每一步所选决策的不同,将随即引起状态的转移,最终在变化的状态中产生一个决策序列。动态规划就是为了使产生的决策序列
在符合某种条件下达到最优。另外,由于动态规划问题具有最优子结构,所以整体中的最优解一定包含子问题的最优解;
如果从图的搜索角度来看,则存在一个状态之间相互连接的有向图,当前状态所做出的每一个可能的决策都或引出一条通向下一状态的边,而且该边具
有权重;动态规划问题即为从初始状态寻找一条通往最终的目标状态的最优路径;在寻找最优路径时,由于最优子结构性质可知,在最优路径中,从初
始状态到最佳路径中的每一个状态的路径都是最佳路径;所以我们需要先寻找出到入射到目标状态的各个前一状态的最佳路径,即求解子问题的最优解;
所以,在该具体的问题中,我们定义序列X=<X1, X2, ..., Xi>和序列Y=<Y1, Y2,..., Yj>中的公共子序列长度为一个状态,即为dp[i, j],每次的决策为判断
X[i]与Y[j]是否相等,如果相等,则引出一条到下一状态dp[i-1, j-1]的边,权重为1,否则会引出两条到下一状态的边,这两个状态分别为dp[i-1, j]与
dp[i, j -1],边的权重都为0;通过从目标状态开始后向求解问题,即要求出从初始状态到目标状态的最优解,则要先求出从目标状态到入射到该目标状态
的前一状态的最优解;
3)问题解答:
由定义的状态以及状态之间的转移所做出的决策,我们可以推断出状态方程: if X[i] == Y[j], dp[i][j] = dp[i-1][j-1] + 1,
否则, dp[i][j] = MAX(dp[i-1][j] , dp[i][j-1]);
代码如下:
#include <iostream> #include <string.h> using namespace std; const int MAX_N = 200 + 10; int dp[MAX_N][MAX_N]; char X[MAX_N], Y[MAX_N]; void Lcs( int XLen, int YLen ) { for ( int i = 1; i <= XLen; ++i ) for( int j = 1; j <= YLen; ++j ) { if ( X[i-1] == Y[j-1] ) dp[i][j] = dp[i-1][j-1] + 1; else if ( dp[i-1][j] >= dp[i][j-1] ) dp[i][j] = dp[i-1][j]; else dp[i][j] = dp[i][j-1]; } } int main() { while ( scanf( "%s %s", X, Y ) != EOF ) { int XLen, YLen; memset( dp, 0, sizeof(dp) ); XLen = strlen( X ); YLen = strlen( Y ); Lcs( XLen, YLen ); printf( "%d ", dp[XLen][YLen] ); } return 0; }