•
/*若給定序列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;
}