最长公共子序列

/*若给定序列X={x1,x2,…,xm},则另一序列Z={z1,z2,…,zk},是X的子序列是指存在一个严格递增下标序列{i1,i2,…,ik}使得对于所有j=1,2,…,k有:zj=xij。例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列,相应的递增下标序列为{2,3,5,7}。 •给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。

•给定2个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找出X和Y的最长公共子序列。

*/

/**********************************************************************
REVISION LOG ENTRY
Revision By: http://blog.csdn.net/hongweijin
Revised on 2005-3-23 16:39:35
Comments: 最长递增序列的动态规划法实现,如序列
1 3 7 4 8 2 9 0 4
其最长子递增序列为:
1 3 4 8
*********************************************************************/


#include <stdio.h>
#include <stdlib.h>

int CreatList(int Source[]);
void GetLongestList(int Source[], int length);

void main()
{
int Source[100];
int length;

length = CreatList(Source);
GetLongestList(Source, length);
}


///////////////////////////////////////////////////////////////////////
//
// 函数名 : GetLongestList
// 功能描述 : 得到最长递增子序列
// 参数 : int Source[]
// 参数 : int length
// 返回值 : void
//
///////////////////////////////////////////////////////////////////////
void GetLongestList(int Source[], int length)
{
int i, j, nextj, * Max, * temp, client = 0, lenTemp;
///////////////////////////////////////////////////////////////////
//Max求值算法:
//通过“动态规划法”:在左面选择一个 ,假设这个点在
//最长子序列里面,那么我可以知道,问题被分成两个部分,前面和
//当前的一个数。假如前面可以给出最优的结构,那么这样加上当前
//点就可以了基于这样的想法,我们有可以从左开始考察,对于第一
//个数,他的最长个数应该为1,那么依次考察下面的元素,在前面是
//最优的情况下,后面的一个元素也可以达到最优。
//递归关系:
//max[i] = MAX(max[j] + 1)
// 1<=j<=i
// Source[j] <= Source[i]
//
//如下面的例子: 1 3 7 4 8 2 9 0 4
//
//其得到的Max值的结果为:1 2 3 3 4 2 5 1 3
//如8这个元素,就有 1 3 4 8 这样的一个数列
///////////////////////////////////////////////////////////////////

Max = (int*)malloc(sizeof(int) * length);
//若Max不予比较都是1个长度
for(i=0; i < length; i++)
Max[i] = 1;
//对所有元素从左到右逐步得到最优解
for (i=0; i < length; i++)
{
//当前i被选中,计算到i为止的最长个数
for (j=0; j<i; j++)
if (Source[i]>Source[j])
{
if (client < Max[j])
client = Max[j];
}
Max[i] += client;/* 获得最优解 */
client = 0;
}
///////////////////////////////////////////////////////////////////
// 在Max数组得到的基础上,可以知道只是个数,不是实际的数列,通过个
// 数可以知道,先扫描得到最大的一个数,那么一定是包含这个数的数列
// 是最大的,然后再向左找次大的,这样就可以从右到左(从大到小)找
// 找到最大的数列,然后用一个数值,将其从小到大输出。
///////////////////////////////////////////////////////////////////
printf("\n打印各元素假设在最长列中时的个数:\n");
for(i=0; i < length; i++)
printf("%d\n", Max[i]);

printf("\n有最长列如下:\n");
client = 0;
for(i=0; i < length; i++)
if (Max[i] > client)
{
client = Max[i];
j = i;
}

//用于对结果的方向调整
lenTemp = client;
temp = (int*)malloc(sizeof(int) * lenTemp);
temp[client] = Source[j];
//打印次小的循环
while(client > 1)
{
--client;
for(i=0; i < j; i++)
{
if (Max[i] == client && Max[j] >= Max[i])
{
temp[client] = Source[i];
nextj = i;
}
}
j = nextj;
}
for(i=1; i <= lenTemp; i++)
{
printf("%d ", temp[i]);
}

printf("\n");
}


///////////////////////////////////////////////////////////////////////
//
// 函数名 : CreatList
// 功能描述 : 输入序列
// 参数 : int Source[100]
// 返回值 : void
//
///////////////////////////////////////////////////////////////////////
int CreatList(int Source[100])
{
int i, j;

printf("请输入序列,并以-1 结束输入:\n");
for(i=0; i < 100; i++)
{
scanf("%d", &j);
if (j == -1)
break;
else
Source[i] = j;
}
return i;
}

你可能感兴趣的:(算法,.net,Blog,zk,J#)