51 Nod 1006 最长公共子序列(LCS & DP)

原题链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1006

题目分析:

首先先知道LCS问题,这有两种: 

  1. Longest Common Substiring —- 最长公共子串 
  2. Longest Common Sequence —- 最长公共子序列

这两者的区别是:前者必须是原字符串中连续的一段,后者可以是在原字符串中随意抽取的一些字符串拼凑成的字符串,只需要遵守顺序即可也就是说:子串字符的位置必须是连续的,子序列不必连续。

这道题目主要考的就是动态规划,具体思路如下:先求出最长公共子序列的长度,然后再根据最长公共子序列的长度逆序求出最长公共子序列。

如果还是理解有些困难的话,可以参考这个递推式

\large C[i, j] = \left\{\begin{matrix} 0 & & (i = 0 \,or\,j = 0 )\\ C[i - 1, j - 1] + 1& & (x_{i} = y_{j})\\ Max(C[i,j - 1],C[i - 1, j])& & (x_{i} \neq y_{j}) \end{matrix}\right.


代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

char a[1005], b[1005];
int dp[1005][1005], la, lb;

void lcs() {                         // 求最长公共子序列长度 
	for (int i = 1; i <= la; i++) {
		for (int j = 1; j <= lb; j++) {
			if (a[i - 1] == b[j - 1])
				dp[i][j] = dp[i - 1][j - 1] + 1;
			else
				dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
		}
	}
}

void solve() {                       // 逆序求出最长公共子序列 
	lcs();
	
	int flag = dp[la][lb];
	char ans[1005] = {'\0'};
	
	while (la && lb) {
		if (a[la - 1] == b[lb - 1] && dp[la][lb] == dp[la - 1][lb - 1] + 1) {
			ans[--flag] = a[la - 1];
			la--;
			lb--;
		} else if (a[la - 1] != b[lb - 1] && dp[la - 1][lb] > dp[la][lb - 1]) {
			la--;
		} else 
			lb--;
	}
	
	cout << ans << endl;
}

int main() {
	while (cin >> a >> b) {
		memset(dp, 0, sizeof(dp));
		
		la = strlen(a);
		lb = strlen(b);
		
		solve();
	}
	return 0;
}

 

posted @ 2018-08-10 10:31  laugh12321  阅读(32)  评论(0编辑  收藏  举报