2014年9月28日 18:35:01

着实是有好几天没有动手写写自己的博客了。这些天感觉自己是被别人的事情搞的一团糟,结果自己反倒是帮不上什么忙的。还是算了吧,先将自己的东西好好的忙好,毕竟还是得自己有能力才能够帮到别人的,没办法,物竞天择适者生存。

好了,ACM也是告了一个段落,结果等来等去等到了算法课,最终是让自己失望万分,还是赶紧的重操旧业把,好好努力,争取让自己搞出一点成绩来,即使最后是失败了,也是虽败犹荣,亮剑精神嘛。

今天研究的问题是最长公共子序列,着实由于基础不扎实,网上找了一篇博客,现在将它的解决方案列举出来:

方法一:枚举法

主要是将第一个串的所有的子序列全部都列举出来,然后和第二个串进行匹配,这个属于暴力破解法。

方法二:动态规划

这里楼主采用的是矩阵的方式来实现的,也就是二维数组。

先是计算最长公共子序列的长度,然后是根据长度回溯出最长公共子序列。

现有两个序列X={x1,x2,x3,...xi},Y={y1,y2,y3,....,yi},

设一个C[i,j]: 保存Xi与Yj的LCS的长度。

递推方程为:

不知道大家看懂了没?动态规划的一个重要性质特点就是解决“子问题重叠”的场景,可以有效的避免重复计算,根据上面的

公式其实可以发现C[i,j]一直保存着当前(Xi,Yi)的最大子序列长度。

 1 #include<stdio.h>
 2 #include<string.h>
 3 char a[30],b[30];
 4 int lena,lenb;
 5 int LCS(int,int);  ///两个参数分别表示数组a的下标和数组b的下标
 6 
 7 int main()
 8 {
 9     strcpy(a,"ABCBDAB");
10     strcpy(b,"BDCABA");
11     lena=strlen(a);
12     lenb=strlen(b);
13     printf("%d
",LCS(0,0));
14     return 0;
15 }
16 
17 int LCS(int i,int j)
18 {
19     if(i>=lena || j>=lenb)
20         return 0;
21     if(a[i]==b[j])
22         return 1+LCS(i+1,j+1);
23     else
24         return LCS(i+1,j)>LCS(i,j+1)? LCS(i+1,j):LCS(i,j+1);
25 }

 下面的这个是根据公式优化出来的代码:

 1 #include <iostream>
 2 #include <string>
 3 #include<stdio.h>
 4 #include<string.h>
 5 
 6 
 7 char a[500],b[500];
 8 char num[501][501]; ///记录中间结果的数组
 9 char flag[501][501];    ///标记数组,用于标识下标的走向,构造出公共子序列
10 void LCS(); ///动态规划求解
11 void getLCS();    ///采用倒推方式求最长公共子序列
12 
13 using namespace std;
14 
15 int main()
16 {
17     int i;
18     strcpy(a,"zhangjie");
19     strcpy(b,"hetongkang");
20     memset(num,0,sizeof(num));
21     memset(flag,0,sizeof(flag));
22     LCS();
23     printf("%d
",num[strlen(a)][strlen(b)]);
24     getLCS();
25     return 0;
26 }
27 
28 void LCS()
29 {
30     int i,j;
31     for(i=1;i<=strlen(a);i++)
32     {
33         for(j=1;j<=strlen(b);j++)
34         {
35             if(a[i-1]==b[j-1])   ///注意这里的下标是i-1与j-1
36             {
37                 num[i][j]=num[i-1][j-1]+1;
38                 flag[i][j]=1;  ///斜向下标记
39             }
40             else if(num[i][j-1]>num[i-1][j])
41             {
42                 num[i][j]=num[i][j-1];
43                 flag[i][j]=2;  ///向右标记
44             }
45             else
46             {
47                 num[i][j]=num[i-1][j];
48                 flag[i][j]=3;  ///向下标记
49             }
50         }
51     }
52 }
53 
54 void getLCS()
55 {
56 
57     char res[500];
58     int i=strlen(a);
59     int j=strlen(b);
60     int k=0;    ///用于保存结果的数组标志位
61     while(i>0 && j>0)
62     {
63         if(flag[i][j]==1)   ///如果是斜向下标记
64         {
65             res[k]=a[i-1];
66             k++;
67             i--;
68             j--;
69         }
70         else if(flag[i][j]==2)  ///如果是斜向右标记
71             j--;
72         else if(flag[i][j]==3)  ///如果是斜向下标记
73             i--;
74     }
75 
76     for(i=k-1;i>=0;i--)
77         printf("%c",res[i]);
78 }
我要坚持一年,一年后的成功才是我想要的。
原文地址:https://www.cnblogs.com/tianxia2s/p/3998817.html