您的位置:首页 > 其它

动态规划——最长公共子序列

2016-03-29 00:00 232 查看
一个数列S,若分别是两个或多个已知序列的子序列,且是所有符合条件序列中最长的,则S称为已知序列的最长公共子序列。

最长公共子串:子串是串的一个连续的部分.

最长公共子序列:子序列则可以不必连续,而从序列中去掉任意的元素而获得新的序列。

//只输出一个序列

#include<iostream>
#include<iostream>
#include<stdio.h>

using namespace std;
static const int max_int = 100;

void LCS(char* str1, char* str2, int m, int n, int c[max_int + 1][max_int + 1], int b[max_int + 1][max_int + 1]) {
int i, j;
for (i = 0; i <= m; i++) c[i][0] = 0;
for (j = 1; j <= n; j++) c[0][j] = 0;
for (i = 1; i <= m; i++) {
for (j = 1; j <= n; j++) {
if (str1[i-1] == str2[j-1]) {//这里下标容易错。
c[i][j] = c[i - 1][j - 1] + 1;
b[i][j] = 0;
}
else {
if (c[i][j - 1]>c[i - 1][j]) {
c[i][j] = c[i][j - 1];
b[i][j] = -1;
}
else {
c[i][j] = c[i - 1][j];
b[i][j] = 1;
}
}
}
}
cout << "最长公共子序列大小为:" << c[m]
<< endl;
}

void Display_LCS(int b[max_int + 1][max_int + 1], char* str1, int i, int j) {
if (i == 0 || j == 0) return;
if (0 == b[i][j]) {
Display_LCS(b, str1, i - 1, j - 1);
cout << str1[i - 1];
}
else if (-1 == b[i][j]) {
Display_LCS(b, str1, i, j - 1);
}
else {
Display_LCS(b, str1, i - 1, j);
}

}

//不用递归,用个链表保存
void showLCS2(const vector<vector<int>> &d, const char *a, int m, int n) {
list<char> ans;
while (m > 0 && n > 0) {
if (d[m]
== 0) {
ans.insert(ans.begin(),a[m]);
--m;
-n;
}
else if (d[m]
== -1) {
--n;
}
else {
--m;
}
}
for_each(ans.begin(), ans.end(), [](char a) {cout << a << endl;});
}

int main() {
char str1[max_int];
char str2[max_int];
scanf("%s", str1);
scanf("%s", str2);
int m = strlen(str1);
int n = strlen(str2);
int c[max_int + 1][max_int + 1];
int b[max_int + 1][max_int + 1];
LCS(str1, str2, m, n, c, b);
Display_LCS(b, str1, m, n);
cout << endl;
return 0;
}

如果要输出所有序列,请参考这篇博客。

str1[i-1]!=str2[j-1]且c[i-1][j]=c[j-1][i]的情况。

http://blog.chinaunix.net/uid-26548237-id-3374211.html

//求取所有的最长公共子序列
#include <iostream>
using namespace std;

const int X = 100, Y = 100;        //串的最大长度
char result[X+1];                    //用于保存结果
int count=0;                        //用于保存公共最长公共子串的个数

/*功能:计算最优值
*参数:
*        x:字符串x
*        y:字符串y
*        b:标志数组
*        xlen:字符串x的长度
*        ylen:字符串y的长度
*返回值:最长公共子序列的长度
*
*/
int Lcs_Length(string x, string y, int b[][Y+1],int xlen,int ylen)
{
int i = 0;
int j = 0;

int c[X+1][Y+1];
for (i = 0; i<=xlen; i++)
{
c[i][0]=0;
}
for (i = 0; i <= ylen; i++ )
{
c[0][i]=0;
}
for (i = 1; i <= xlen; i++)
{

for (j = 1; j <= ylen; j++)
{
if (x[i - 1] == y[j - 1])
{
c[i][j] = c[i-1][j-1]+1;
b[i][j] = 1;
}
else
if (c[i-1][j] > c[i][j-1])
{
c[i][j] = c[i-1][j];
b[i][j] = 2;
}
else
if(c[i-1][j] < c[i][j-1])
{
c[i][j] = c[i][j-1];
b[i][j] = 3;
}
else
{
c[i][j] = c[i][j-1]; //或者c[i][j]=c[i-1][j];
b[i][j] = 4;
}
}
}
cout << "计算最优值效果图如下所示:" << endl;
for(i = 1; i <= xlen; i++)
{
for(j = 1; j < ylen; j++)
{
cout << c[i][j] << " ";
}
cout << endl;
}
return c[xlen][ylen];
}

/*功能:计算最长公共子序列
*参数:
*        xlen:字符串x的长度
*        ylen:字符串y的长度
*        x    :字符串x
*        b:标志数组
*        current_len:当前长度
*        lcs_max_len:最长公共子序列长度
*
*/
void Display_Lcs(int i, int j, string x, int b[][Y+1],int current_len,int lcs_max_len)
{
if (i ==0 || j==0)
{
for(int s=0; s < lcs_max_len; s++)
{
cout << result[s];
}
cout<<endl;
count++;
return;
}
if(b[i][j]== 1)
{
current_len--;
result[current_len]=x[i- 1];
Display_Lcs(i-1, j-1, x, b,current_len,lcs_max_len);
}
else
{
if(b[i][j] == 2)
{
Display_Lcs(i-1, j, x, b,current_len,lcs_max_len);
}
else
{
if(b[i][j]==3)
{
Display_Lcs(i, j-1, x, b,current_len,lcs_max_len);
}
else
{
Display_Lcs(i,j-1,x,b,current_len,lcs_max_len);
Display_Lcs(i-1,j,x,b,current_len,lcs_max_len);
}
}
}
}

int main(int argc, char* argv[])
{
string x = "ABCBDAB";
string y = "BDCABA";
int xlen = x.length();
int ylen = y.length();

int b[X + 1][Y + 1];

int lcs_max_len = Lcs_Length( x, y, b, xlen,ylen );
cout << lcs_max_len << endl;

Display_Lcs( xlen, ylen, x, b, lcs_max_len, lcs_max_len );
cout << "共有:" << count << "种";

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: