问题描述:
给定两个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找出X和Y的最长公共子序列。(给定两个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。)
细节须知(与之前随笔的对比):
将由数组存储起来一并输出至文件修改为边运行边输出,增加了程序的鲁棒性。
算法原理:
a.最长公共子序列的结构
对X的所有子序列,检查它是否也是Y的子序列,从而确定它是否为X和Y的公共子序列。并且在检查过程中记录最长的公共子序列。X的所有子序列都检查过后即可求出X和Y的最长公共子序列。X的每个子序列相应于下标集{1,2,…,m}的一个子集。
b.子问题的递归结构
要找出X和Y的最长公共子序列,可按以下方式递归计算:当xm=yn时,找出Xm-1和Yn-1的最长公共子序列,然后在其尾部加上xm(=yn)即可得到X和Y的最长公共子序列。当xm≠yn时,必须解两个子问题,即找出Xm-1和Y的一个最长公共子序列及X和Yn-1的一个最长公共子序列。这两个公共子序列中较长者即为X和Y的最长公共子序列。
c.计算最优值
利用动态规划算法自底向上地计算最优值。
d.构造最长公共子序列
首先从b[m][n]开始,依其值在数组b中搜索。当b[i][j]=1时,表示Xi和Yj的最长公共子序列
1 #include<cstdio> 2 #include<cstring> 3 #include<stack> 4 #include<ctime> 5 #include<iostream> 6 #include<fstream> 7 #include<algorithm> 8 #include<windows.h> 9 using namespace std; 10 LARGE_INTEGER nFreq;//LARGE_INTEGER在64位系统中是LONGLONG,在32位系统中是高低两个32位的LONG,在windows.h中通过预编译宏作定义 11 LARGE_INTEGER nBeginTime;//记录开始时的计数器的值 12 LARGE_INTEGER nEndTime;//记录停止时的计数器的值 13 #define N 10000 14 //const int SIZE_CHAR = 10000; //生成32 + 1位C Style字符串 15 const char CCH[] = "_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"; 16 int dp[N][N]; 17 char c; 18 int main(void) 19 { 20 //char a[N]; 21 //char b[N]; 22 //char a[SIZE_CHAR+2]; 23 //char b[SIZE_CHAR+2]; 24 ofstream fout; 25 int m = 0,i = 0; 26 int SIZE_CHAR; 27 cout<<"Please enter the number of times you want to run the program:"; //输入程序运行次数 28 cin>>m; 29 //int SIZE[m]; 30 double cost; 31 //double runtime[m]; 32 srand((unsigned)time(NULL)); 33 fout.open("data.txt",ios::app); 34 if(!fout){ 35 cerr<<"Can not open file 'data.txt' "<<endl; 36 return -1; 37 } 38 fout.setf(ios_base::fixed,ios_base::floatfield); //防止输出的数字使用科学计数法 39 for(i = 0; i < m; i++){ 40 //SIZE_CHAR=10000+RAND_MAX*(rand()%300)+rand(); //RAND_MAX=32767,随机生成数据量 41 SIZE_CHAR = rand() % 10000; 42 fout<<SIZE_CHAR<<","; 43 // SIZE[i]=SIZE_CHAR; //限定数据规模为10000~9872867 44 char a[SIZE_CHAR + 1] = {'