第15章DP(转)

15.1-1 由公式(15.3)和初始条件T(0) = 1,证明公式(15.4)成立。

ANSWER:

 15.1-2 举反例证明下面的“贪心”策略不能保证总是得到最优切割方案。定义长度为i的钢条的密度为Pi / i,即每英寸的价值。贪心策略将长度为n的钢条切割下长度为i (1 ≤ i ≤ n)的一段,其密度最高。接下来继续使用相同的策略切割长度为n-i的剩余部分。

ANSWER:当长度n = 4时,按照“贪心”策略则切割成长度为1和3的钢条(p = 1 + 8 = 9);而最优解为切割成2条长度为2的钢条(p = 5 + 5 = 10 > 9)。

 15.1-3 我们对钢条切割问题进行一点修改,除了切割下的钢条段具有不同价值Pi外,每次切割还要付出固定的成本c。这样,切割方案的收益就等于钢条段的价格之和减去切割成本。设计一个动态规划算法解决修改后的钢条切割问题。

ANSWER:多新建一个数组m[0...n]记录每个长度的钢条最优解的切割段数,当完成长度为i的钢条最优解时,更新长度为i+1时使m[i+1] = m[j] + 1,其中长度为i+1的钢条切割成长度为(i+1-j)和j的两大段,长度为j的钢条继续切割。

               BOTTOM_UP_CUT_ROD_COST(p, n, c):  
  1.     let r[0...n] and m[0...n] be new arrays  
  2.     r[0] = 0, m[0] = 0  
  3.     for i = 1 to n  
  4.         q = -∞  
  5.         for j = 1 to i  
  6.             if q < p[j] + r[i-j] - m[i-j]*c  
  7.                 q = p[j] + r[i-j] - m[i-j]*c  
  8.                 m[i] = m[i-j] + 1  
  9.         r[i] = q  
  10.     return r[n]
 
//15.1-3带有固定切割成本的钢条切割方案
#if 0
#include <iostream>
using namespace std;
int Max(int a,int b)
{
    return a>b?a:b;
}
struct array
{
    int r;//代表最大收益
    int s;//代表切割方案
};
struct array *EXTENDED_BOTTOM_UP_CUT_ROD(int p[],int n)
{
    struct array *rs=new struct array[n];
    rs[0].r=0;
    int q;
    for (int j=0;j<n;j++)
    {
        int flag=1;//哨兵为1代表无切割。
        q=p[j];
        for (int i=0;i<j;i++)
        {
            //q=Max(q,p[i]+rs[j-i].r-1);
            if(q<=p[i]+rs[j-i].r-1)//切割固定成本c=1
            {
                q=p[i]+rs[j-i].r-1;
                rs[j+1].s=i+1;
                flag=0;//哨兵为0代表有切割。
            }
        }
        if (j==i)//i=j代表无切割
        {
            if (q<=p[i]+rs[j-i].r&&flag)
            {//无切割时注意切割方案就等于钢条长度。
                rs[j+1].s=i+1;
            }
        }
        rs[j+1].r=q;
    }
    return rs+n;
}
void PRINT_CUT_ROD_SOLUTION(int p[],int n)
{
    struct array *rs=EXTENDED_BOTTOM_UP_CUT_ROD(p,n);
    while (n>0)
    {
        cout<<(*rs).s<<" ";
        n=n-(*rs).s;
        rs=rs-(*rs).s;
    }
}
void main()
{
    const int n=10;
    int p[10]={1,5,8,9,10,17,17,20,24,30};
    cout<<(*EXTENDED_BOTTOM_UP_CUT_ROD(p,10)).r<<endl;
    PRINT_CUT_ROD_SOLUTION(p,10);
}
View Code

 

15.1-4 修改MEMOIZED-CUT-ROD,使之不进返回最优收一只,还返回切割方案。

ANSWER:利用数组s的结果可以得到切割方案,新建存储长度为n的钢条切割方案数组t[0...n]

         CUT_WAY(s, n):  

  1.     i = 0  
  2.     while n > 0  
  3.         t[i] = s[n]  
  4.         n = n - s[n]  
  5.         i = i + 1  
  6.     return t[0...i-1]
 1 //15.1-4动态规划法递归求解最优钢条切割问题。不仅返回收益还返回切割方案。
 2 #include <iostream>
 3 using namespace std;
 4 struct array
 5 {
 6     int r;//代表最大收益
 7     int s;//代表切割方案
 8 };
 9 int Max(int a,int b)
10 {
11     return a>b?a:b;
12 }
13 struct array *MEMOIZED_CUT_ROD_AUX(int p[],int n,struct array rs[])
14 {
15     static int q;
16     if (rs[n].r>=0)
17     {
18         return rs+n;
19     }
20     if (n==0)
21     {
22         q=0;
23     } 
24     else
25     {
26         q=-0x7fffffff;
27         for (int i=0;i<n;i++)
28         {
29             int t=p[i]+MEMOIZED_CUT_ROD_AUX(p,n-i-1,rs)->r;
30             if (q<t)
31             {
32                 q=t;
33                 rs[n].s=i+1;//n相当于上面迭代里的j+1,i+1和上面迭代一样。
34             }
35         }
36     }
37     rs[n].r=q;
38     return rs+n;
39 }
40 struct array *MEMOIZED_CUT_ROD(int p[],int n)
41 {
42     struct array *rs=new struct array [n];
43     for (int i=0;i<=n;i++)
44     {
45         rs[i].r=-0x7fffffff;
46     }
47     return MEMOIZED_CUT_ROD_AUX(p,n,rs);
48 }
49 void PRINT_CUT_ROD_SOLUTION(int p[],int n)
50 {
51     struct array *rs=MEMOIZED_CUT_ROD(p,n);
52     cout<<"最大收益:"<<rs->r<<endl;
53     cout<<"切割方案:";
54     while (n>0)
55     {
56         cout<<(*rs).s<<" ";
57         n=n-(*rs).s;
58         rs=rs-(*rs).s;
59     }
60 }
61 void main()
62 {
63     const int n=10;
64     int p[10]={1,5,8,9,10,17,17,20,24,30};
65     PRINT_CUT_ROD_SOLUTION(p,10);
66     cout<<endl;
67 }
View Code

 

15.1-5 斐波那契数列可以用递归式(3.22)定义。设计一个O(n)时间的动态规划算法计算第n个斐波那契数。画出字问题图。图中有多少顶点和边?

ANSWER:O(n)时间,O(1)空间

  1. On_for_Fibonacci_sequence(n):  
  2.     if n <= 2  
  3.         return 1  
  4.     x = 1, y = 1  
  5.     for i = 3 to n  
  6.         res = x + y  
  7.         x = y  
  8.         y = res  
  9.     return res

子问题图:

 

图中有n个顶点,(2n-3)条边。

 

15.2-1 对矩阵规模序列{5,10,3,12,5,50,6},求矩阵链最优括号化方案。

利用上面代码:得到下图所示结果:

15.2-2设计递归算法MATRIX-CHAIN-MULTIPLY(A,s,i,j),实现矩阵链最优代价乘法计算的真正计算过程,其输入参数为矩阵序列{A1,A2,...,An},MATRIX-CHAIN-ORDER得到的表s,以及下标i和j.(初始调用应为MATRIX-CHAIN-MULTIPLY(A,s,1,n)).

  1 #include <iostream>
  2 using namespace std;
  3 #define n 5//可以更改矩阵的数量
  4 struct Matrix
  5 {
  6     int rows;//表示行数。
  7     int columns;//表示列数。
  8     int **M;
  9     Matrix(int i=0,int j=0)
 10     {
 11       rows=i;
 12       columns=j;
 13       M=new int *[rows];
 14       for (int k=0;k<rows;k++)
 15       {
 16            M[k]=new int [columns];
 17       }
 18     };
 19 };
 20 struct Matrix_CHAIN//矩阵链
 21 {
 22      int **m;//运算次数
 23      int **s;//划分方式    
 24      Matrix_CHAIN()
 25      {
 26          m=new int *[n-1];
 27          for (int k=0;k<n-1;k++)
 28          {
 29              m[k]=new int [n-1];
 30          }
 31          s=new int *[n-2];
 32          for (int t=0;t<n-1;t++)
 33          {
 34              s[t]=new int [n-1];
 35          }
 36      }
 37 };
 38 struct Matrix init(struct Matrix A)
 39 {
 40     for (int i=0;i<A.rows;i++)
 41     {
 42         for (int j=0;j<A.columns;j++)
 43         {
 44             A.M[i][j]=rand()%10;
 45         }
 46     }
 47     return A;
 48 }
 49 struct Matrix Matrix_MULTIPLY(struct Matrix A,struct Matrix B)
 50 {
 51    if (A.columns!=B.rows)
 52    {
 53        struct Matrix D(1,1);
 54        D.M[0][0]=0;
 55        cerr<<"incompatible dimensions"<<endl;
 56        return D;
 57    } 
 58    else
 59    {
 60        struct Matrix C(A.rows,B.columns);
 61          for (int i=0;i<A.rows;i++)
 62          {
 63              for (int j=0;j<B.columns;j++)
 64              {
 65                  C.M[i][j]=0;
 66                  for (int k=0;k<A.columns;k++)
 67                  {
 68                      C.M[i][j]=C.M[i][j]+A.M[i][k]*B.M[k][j];
 69                  }
 70              }
 71          }
 72          return C;
 73    }
 74 }
 75 struct Matrix_CHAIN MATRIX_CHAIN_ORDER(int p[])
 76 {
 77     int N=n-1;
 78     Matrix_CHAIN T;
 79     for (int i=0;i<N;i++)
 80     {
 81         T.m[i][i]=0;
 82     }
 83     for (int l=2;l<=N;l++)
 84     {
 85         for (int i=1;i<=N-l+1;i++)
 86         {
 87             int j=i+l-1;
 88             T.m[i-1][j-1]=0x7fffffff;
 89             for (int k=i;k<=j-1;k++)
 90             {
 91                 int q=T.m[i-1][k-1]+T.m[k][j-1]+p[i-1]*p[k]*p[j];
 92                 if (q<T.m[i-1][j-1])
 93                 {
 94                     T.m[i-1][j-1]=q;
 95                     T.s[i-1][j-1]=k-1;
 96                 }
 97             }
 98         }
 99     }
100     return T;
101 }
102 //15.2-2矩阵链总乘法
103 struct Matrix MATRIX_CHAIN_MULTIPLY(Matrix A[],Matrix_CHAIN T,int i,int j)
104 {
105     if (j==i)
106     {
107         return A[i];
108     }
109     if (j==i+1)
110     {
111         return Matrix_MULTIPLY(A[i],A[j]);
112     }
113     Matrix t1=MATRIX_CHAIN_MULTIPLY(A,T,i,T.s[i][j]);
114     Matrix t2=MATRIX_CHAIN_MULTIPLY(A,T,T.s[i][j]+1,j); 
115     return Matrix_MULTIPLY(t1,t2);
116 }
117 void PRINT_OPTIMAL_PARENS(Matrix_CHAIN T,int i,int j)
118 {
119    if (i==j)
120    {
121        cout<<"A"<<i;
122    } 
123    else
124    {
125        cout<<"(";
126        PRINT_OPTIMAL_PARENS(T,i,T.s[i][j]);
127        PRINT_OPTIMAL_PARENS(T,T.s[i][j]+1,j);
128        cout<<")";
129    }
130 }
131 void Print(struct Matrix A)
132 {
133     for (int i=0;i<A.rows;i++)
134     {
135         for (int j=0;j<A.columns;j++)
136         {
137             cout<<A.M[i][j]<<" ";
138         }
139         cout<<endl;
140     }
141 }
142 void main()
143 {
144     //int p[n]={5,10,3,12,5,50,6};
145     //int p[n]={30,35,15,5,10,20,25};
146     int p[n]={2,3,4,5,6};
147     struct Matrix_CHAIN T=MATRIX_CHAIN_ORDER(p);
148     for (int i=0;i<n-1;i++)
149     {
150         for (int j=0;j<n-1;j++)
151         {
152             if (T.m[i][j]<0)
153             {
154                 cout<<"-1"<<"\t";
155             }
156             else cout<<T.m[i][j]<<"\t";
157         }
158         cout<<endl;
159     }
160     PRINT_OPTIMAL_PARENS(T,0,n-2);
161     struct Matrix A[n]={0};
162     for (int j=1;j<n;j++)
163     {
164         struct Matrix t(p[j-1],p[j]);
165         A[j-1]=t;
166         init(A[j-1]);
167         cout<<endl;
168         Print(A[j-1]);
169         cout<<endl;
170     }
171     struct Matrix C=MATRIX_CHAIN_MULTIPLY(A,T,0,n-2);
172     Print(C);
173 }
View Code

由于数组下标是从0开始的,所以 这里调用应为MATRIX-CHAIN-MULTIPLY(A,s,0,n-2)).n为矩阵链元素个数,上面代码中的n为矩阵链长度,实际矩阵个数N=n-1个。

15.2-3 用代入法证明递归公式(15.6)的结果为Ω(2^n).

P(n-1)=P(1)P(n-2)+P(2)P(n-3)+....+P(n-2)P(1)    P(n)=P(1)P(n-1)+P(2)P(n-2)+....+P(n-1)P(1)   因为P(1)<P(2)<...P(n-1) 所以P(n)>P(1)P(n-1)+P(n-1)   因为P(1)=1 P(n)>2P(n-1)

猜想P(n)>c2^n,则P(n-1)>c2^(n-1) 所以P(n)>2c2^(n-1)=c2^n 得证!

15.2-4 对输入链长度为n的矩阵连乘法问题,描述其子问题图:它包含多少个顶点?包含多少条边?这些分别连接哪些顶点?

包含n²个顶点,n³条边连接着n²个顶点。

15.2-5 令R(i,j)表示在一次调用MATRIX-CHAIN-ORDER过程中,计算其他表项时访问表项m[i,j]的次数。证明:(提示:证明中可用到公式A.3)

15.2-6 证明:对n个元素的表达式进行完全括号化,恰好需要n-1对括号。

     利用归纳法即可证明。当n≤2时 恰好有1对括号。假设当n=k(2<k<n)时,有k-1对括号。则n=k+1时,现在我们把这k+1个矩阵分成k个矩阵+1个矩阵,前k个矩阵在前面假设中已知只要加k-1对括号就可以使最终结果是最优的,那么保持前k个矩阵的括号划分,并且得到最优结果矩阵后,再与第k+1个矩阵相乘,这时问题又转化为2个矩阵相乘的简单问题了,由前面已知需要1对括号,那么总的括号就是k-1+1=k对括号,在n=k+1时,也成立。所以利用归纳法得证!

 

15.3动态规划原理

15.3-1对于矩阵链乘法问题,下面两种确定最优代价的方法哪种更高效?第一种方法是穷举所有可能的括号化方案,对每种方案计算乘法运算次数,第二种方法是运行RECURSIVE-MATRIX-CHAIN。证明你的结论。

书中对枚举法已经给出其运行时间,就是类似卡塔兰数的序列,运算次数为Ω(4^n/n^(3/2))。而用朴素递归方式求全部解的运算次数为O(n3^n).显然用递归方式求解更高效。

15.3-2 对一个16个元素的数组,画出2,.3-1节中MERGE-SORT过程运行的递归调用树。解释备忘技术为什么对MERGE-SORT这种分治算法无效。

参考书中图2-4,这里只是把原书8个元素扩展到16个元素,两者类似。由2-4图可以看出,每个子问题都是全新的,不存在重叠子问题,所以图中问题适合分治而不适合动态规划。

15.3-3 考虑矩阵链乘法问题的一个变形,目标改为最大化矩阵序列括号花方案的变量乘法运算次数,而非最小化。此问题具有最优子结构性质吗?

由于矩阵链中的子问题链为AiAi+1...Ak和Ak+1Ak+2....Aj的乘法问题,子链是互不相交的,因此任何矩阵都不会同时包含在两个子链中。这样我们说矩阵链子问题是无关的。于是我们可以用“剪切-黏贴”技术来加以证明这个事具有最优子结构的。

15.3-3思路供参考:确定一个问题是否具有最优子结构要考虑两个方面的问题:1、子问题是否是独立。2、子问题是否是重叠
先分析第一个问题:最大矩阵链乘法子问题是将矩阵链分为两部分,求前一部和后一部分最大值,然后合并,而这两个子问题的 最大值是在两个矩阵链中分别求解,所以这两个子问题没有重复(在这里最鲜明的对照就是无权图中最长简单路径问题,该问题如果分为两个子问题,前一部分的最长路径可能包含后一部分的最长路径,两个子问题合并之后的路径就不是简单路径了)。再看子问题是否重叠,如果子问题中的子问题是一个跟子问题不一样的问题则为不重叠,如果将子问题的矩阵链分解为两个孙矩阵链,同样是求两个孙矩阵链各自的最大值然后合并,该孙子问题与子问题相同,即为重叠,所以最大矩阵链乘法具有最优子结构。

代码如下:

#include<iostream>
using namespace std;
//p为矩阵链,p[0],p[1]代表第一个矩阵,p[1],p[2]代表第二个矩阵,length为p的长度
//所以如果有六个矩阵,length=7,m为存储最优结果的二维矩阵,t为存储选择最优结果路线的
//二维矩阵
void MatrixChainOrder(int *p,int (*m)[10],int (*t)[10],int length)
{
    int n=length-1;
    int i,j,k,q,num=0;
    //A[i][i]只有一个矩阵,所以相乘次数为0,即m[i][i]=0;
    for(i=1;i<length;i++)
    {
        m[i][i]=0;
    }
    //i代表矩阵链的长度,i=2表示有两个矩阵相乘时如何划分
    for(i=2;i<=n;i++)
    {
        //j表示从第j个矩阵开始的i个矩阵如何划分是最优
        for(j=1;j<=n-i+1;j++)
        {
            //k为从第j个数i个矩阵就是k,从j到k表示他们之间的i个矩阵如何划分
            k=j+i-1;
            //m[j][k]存储了从j到k使用最佳划分所得到的最优结果
            m[j][k]=0;
            //q为介于j到k-1之间的数,目的是利用q对j到k之间的矩阵进行试探性的划分,
            //从而找到最优划分,这是一种遍历性的试探。
            for(q=j;q<=k-1;q++)
            {
                num=m[j][q]+m[q+1][k]+p[j-1]*p[q]*p[k];
                if(num>m[j][k])
                {
                    m[j][k]=num;
                    t[j][k]=q;
                }
            }
        }
    }
}
void PrintAnswer(int(*t)[10],int i,int j)
{
    if(i==j)
    {
        cout<<"A"<<i;
    }
    else
    {
        cout<<"(";
        PrintAnswer(t,i,t[i][j]);
        PrintAnswer(t,t[i][j]+1,j);
        cout<<")";
    }
}
int main()
{
    int p[7]={30,35,15,5,10,20,25};
    int m[10][10],t[10][10];
    MatrixChainOrder(p,m,t,7);
//    MemorizedMatrixChain(p,m,t,7);
    PrintAnswer(t,1,6);
    cout<<endl;
    cout<<m[1][6]<<endl;
    return 0;
}
View Code

 15.3-4 <1,1,2,3> 

贪心:[1,3]=[1,1]+[2,3]+1*1*3=1*2*3+3=9
正确结果:[1,3]=[1,2]+[3,3]+1*2*3=1*1*2+6=8

15.3-5 对15.1节的钢条切割问题加入限制条件:假定对于每种钢条长度i(i=1,2,...n-1),最多允许切割出li段长度为i的钢条。证明:15.1节所描述的最优子结构性质不再成立。

从图中看出如果切割1个长度为4的钢条,最佳切割方式是切成4条长度为1的钢条可以获得60最大收益,但是我们给每种长度对应的条数做了限制,比如长度为1的钢条最多只能切割2段,那么4>2超出预期。所以我们在不违反切割限制前提下只能选择切成长度分别为1,1和2的钢条作为最佳切割方式,收益为50。由于加了切割限制,所以最优子结构性质不再成立。

最优子结构:问题的最优解由相关子问题的最优解组合而成,而这些子问题可以独立求解。
因为此时每种长度的切割数被限制,也就是说此时使用长度i时,会影响子问题的li 大小,是相关的(可以把每种长度的限制加入状态中,来消除相关性。但维数太多无法实现)。即建立[rn ,L],L为li 集合,但是子问题的状态数很大,几乎等于穷举了

15.3-6

Dm =max{(Di -ci )ri,j }=max{Diri,j -ci *ri,j },两个子问题相关,具有同样变量ri,j

15.4.1

15.4-2

//LCS
#include<iostream>
#include<string>
using namespace std;

//改进的LCS算法,不使用数组b便可打印出结果
void LCS_LengthC(string x,string y,int (*c)[100])
{
    int m,n;
    m=x.length();
    n=x.length();
    int i,j;
    //如果i或j等于0则c[i][j]=0;
    for(i=1;i<=m;i++)
    {
        c[i][0]=0;
    }
    for(i=1;i<=n;i++)
    {
        c[0][i]=0;
    }
    //遍历两个字符串,依次标记c[i][j],c[i][j]标记了从x的开始到第i个元素与从
    //y开始到第j个元素中LCS的长度
    //数组b用来标记最长公共子串所要走的路线,该路线为两个字符串组成的矩阵中的对应的字母
    for(i=1;i<=m;i++)
    {
        for(j=1;j<=n;j++)
        {
            if(x[i-1]==y[j-1])
            {
                c[i][j]=c[i-1][j-1]+1;
            }
            else
            {
                if(c[i][j-1]>c[i-1][j])
                {
                    c[i][j]=c[i][j-1];
                }
                else
                {
                    c[i][j]=c[i-1][j];
                }
            }
        }
    }
}
void PrintAnswerC(string x,string y,int(*c)[100],int i,int j)
{
    if(i==0||j==0)
    {
        return ;
    }
    else
    {
        if(x[i-1]==y[j-1])
        {
            PrintAnswerC(x,y,c,i-1,j-1);
            cout<<x[i-1]<<" ";
        }
        else if(c[i-1][j]>=c[i][j-1])
        {
            PrintAnswerC(x,y,c,i-1,j);
        }
        else
        {
            PrintAnswerC(x,y,c,i,j-1);
        }
    }
}
int main()
{
    string x="abcbda";
    string y="bdcaba";
    int c[100][100]={0};
    int b[100][100]={0};
    LCS_LengthC(x,y,c);
    cout<<"the LCS is: "<<c[x.length()][y.length()]<<endl;
    PrintAnswerC(x,y,c,x.length(),y.length());
    return 0;

}
View Code

15.4-3

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

int lcsLength(int **c,char *x,char *y,int i,int j)
{
    if(i<0 || j<0)
        return -1;
    if(c[i][j] != -1)
        return c[i][j];
    if(x[i-1]==y[j-1])
    {
        int a=lcsLength(c,x,y,i-1,j-1);
        c[i][j]=a+1;        
    }
    else
    {
        int up=lcsLength(c,x,y,i-1,j);
        int left=lcsLength(c,x,y,i,j-1);
        if(up>=left)
            c[i][j]=up;    
        else
            c[i][j]=left;
    }
    return c[i][j];
}

int** initC(char *x,char *y)
{
    int xlen=strlen(x);
    int ylen=strlen(y);
    int **c=(int**)malloc((xlen+1)*sizeof(int*));
    for(int i=0;i<xlen+1;i++)
    {
        c[i]=(int*)malloc((ylen+1)*sizeof(int));
    }
    for(int i=0;i<xlen+1;i++)
        for(int j=0;j<ylen+1;j++)
            c[i][j]=-1;
    for(int i=0;i<xlen+1;i++)
        c[i][0]=0;
    for(int j=0;j<ylen+1;j++)
        c[0][j]=0;
    return c;
}

void printLCS(int **c,char *x,char *y)  
{  
    int xlen=strlen(x);  
    int ylen=strlen(y);  
    int i=xlen,j=ylen;  
    char *s=(char*)malloc((xlen)*sizeof(char));  
    while(i>=1 && j>=1)  
    {  
        if(x[i-1]==y[j-1])  
        {  
            s[i-1]=x[i-1];  
            i--;  
            j--;  
        }  
        else if(c[i][j]==c[i-1][j])  
        {  
            s[i-1]='*';  
            i--;              
        }  
        else  
            j--;  
    }  
    for(;i<xlen;i++)  
    {  
        if(s[i]!='*')  
            printf("%c ",s[i]);  
    }  
    printf("\n");
} 

void printC(int **c,int xlen,int ylen)
{
    for(int i=1;i<xlen+1;i++)
    {
        for(int j=1;j<ylen+1;j++)
        {
            if(c[i][j]==-1)
                printf("%d ",c[i][j]);
            else
                printf("%d  ",c[i][j]);
        }
        printf("\n");
    }
}

void main()
{
    char *x="ABCBDAB";
    char *y="BDCABA";
    int **c=initC(x,y);
    lcsLength(c,x,y,strlen(x),strlen(y));
    printLCS(c,x,y);
    //printC(c,strlen(x),strlen(y));
    getchar();
}
View Code

 

posted @ 2017-10-19 14:58  miaoheping  阅读(2046)  评论(0编辑  收藏  举报