POJノース1458(fjutacm 1386)最長共通部分列LCS DP

問題の説明は、
最大長のXとYの長さ一般的なシーケンスを求めて、二つの配列XとYを考えます。

以下に定義されるサブシーケンスは、厳密に増加指数<I1、I2、I3、I4、... IM>のセットを選択します

添え字を構成する要素にこれらの新しい配列は元の配列のサブ配列であり、

配列Z例えば、シーケンス後にX = <A、B、C、F、B、C>、選択指数<1、2、4、6>得= <A、B、F、C> Xの息子配列の一つ

入力
プログラムの入力は、STDの入力からです。入力に設定された各データは、所定のシーケンスを表す2つの文字列を含みます。配列は、空白の任意の数によって分離されています。入力データが正確である。
字符串长度小于等于1000年

出力
データの各セットの標準出力にプログラムプリント別の行の先頭から最大長共通サブシーケンスの長さ。

SampleInput
abcfbc abfcab
プログラミングコンテスト
ABCD MNP

SampleOutput
4
2
0

この質問は、古典的なLCS(最長共通部分)最長共通部分列問題、使用または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