最長公共子序列

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章