POJ北大 1458 (fjutacm 1386)最长公共子序列 LCS dp

Problem Description
给定两个序列X和Y,求X和Y的最大长度公共子序列的长度。

一个序列的子序列,定义如下,选取一组严格递增的下标<i1,i2,i3,i4,……im>

则这些上标上的元素构成的新序列就是原序列的子序列,

比如序列 X = < a, b, c, f, b, c > ,选取下标 < 1, 2, 4, 6 >.后得到的序列Z=<a,b,f,c>就是X的子序列之一

Input
The program input is from the std input. Each data set in the input contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct.
字符串长度小于等于1000

Output
For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.

SampleInput
abcfbc abfcab
programming contest
abcd mnp

SampleOutput
4
2
0

这题就是经典的LCS(Longest Common Substring)最长公共子序列问题,用的还是dp动态规划的算法。dp的话还是直接结合代码和案例理解,上代码、注释!

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <algorithm>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <math.h>
#include <iostream>
const int inf=1<<31;
const int MAX=1e3+5;
using namespace std;

char x[MAX],y[MAX];
int lcs[MAX][MAX];
int main()
{
  int i, j, lenx, leny;
	while(cin>>x>>y)
	{
	  memset(lcs, 0, sizeof(lcs));
    lenx = strlen(x);
    leny = strlen(y);
		for(i=1; i<=lenx; i++)  /// 这里的嵌套循环,就是拿x中的每一个字符到y中遍历
			for(j=1; j<=leny; j++)///一遍
			{
				if(x[i-1]==y[j-1])              /// 如果找到相同的字符,我们就在前一个
					lcs[i][j] = lcs[i-1][j-1] + 1;///位置的上一个状态的最优解上+1
				else                                        /// 如果没有,直接从前一个
					lcs[i][j] = max(lcs[i-1][j], lcs[i][j-1]);///位置和上一个状态之间取最
                                                    ///优解
			}/// 这里lcs dp的过程,我们可以理解成这样,以这组案例为例
       /**
       abcfbc         abfcab
         j 0 1 2 3 4 5 6
       i=0 0 0 0 0 0 0 0
       i=1 0 1 1 1 1 1 1
       i=2 0 1 2 2 2 2 2
       i=3 0 1 2 2 3 3 3
       i=4 0 1 2 3 3 3 3
       i=5 0 1 2 3 3 3 4
       i=6 0 1 2 3 4 4 4
       **/
      /// 其实就跟背包dp一个感觉,这一个状态只与上一个状态有关。在保证前面所
      ///有位置都已经处理为当时最优解的情况下,如果我找到与x[i]相同的y[j](其
      ///实是i-1和j-1,因为dp的时候我们是从1开始的。这里用i和j比较方便),这
      ///时候我有两种选择,一种是认定它就是我们要确定的位置,比如案例中x中的
      ///第一个c,这时候我们就选择在找到它之前的状态上,也就是lcs[i-1][j-1]上
      ///+1,看作是最终答案的、ab的下一位;还有一种选择其实会在之后生效,就
      ///比如案例中的正解,就是取y的后一个c,才能让f也被包含。

      /// 这样说有点抽象,直接回到上面的案例流程。前面的ab没有问题,直到i=3,
      ///也就是拿x中i-1上的c到y中遍历时,我们在j=4,也就是y中第一个c的位置上
      ///取上一个状态的前一个位置lcs[2][3]的2,+1接续上去,这样lcs[3][4]就变
      ///成了3,也就是说当前最长的公共子序列长度可以确定为3了,abc。
      ///再往下走,我们发现i=4的f也在j=3处找到了相同的,那同理我们还是找到上
      ///一个状态的前一个位置lcs[3][2],发现那时候最长也还是只有2,ab,因为f
      ///的位置毕竟在第一个c前面,所以不会出现4,当前最优依然是3,abc或abf。
      ///这样遍历下去,最终的结果是abfc或abfb,反正答案就是lcs[lenx][leny]=4。

//		for (i=0; i<=lenx; i++)
//    {
//      for (j=0; j<=leny; j++)
//        printf("%d ", lcs[i][j]);
//      printf("\n");
//    }
/// 可以自己打表看一下LCS dp的过程
		cout << lcs[lenx][leny] << endl;
	}
	return 0;
}

发布了19 篇原创文章 · 获赞 0 · 访问量 499

猜你喜欢

转载自blog.csdn.net/qq_43317133/article/details/99702657