动态规划解最大回文子序列

子串和子序列有区别,子串是连续的,子序列不一定连续。

例如字符串 "bdsdksldjfkdls",它的一个子串为"dsdk",它的一个子序列为"bdklj"(1,2,5,7,9)。

一:刻画最优解的结构特征

假设序列为a,从a[i]到a[j]所包含的最大回文子序列的字符数为c[i,j],则所求的就是c[i,j]第一次取到最大值时的子序列。之所以是第一次取到最大值,是因为c[i,j+1]只可能大于等于c[i,j],若c[i,j]已经取到了最大值,那么a[i]和a[j]就是最大回文子序列的首尾,a[j+1]则不在该子序列中。

二:递归定义最优解的值

最优解的值是c[i,j],最优解是子序列,这二者是不一样的。

c[i,j] = c[i+1,j-1]+2 (a[i] = a[j])

c[i,j] = max(c[i+1,j],c[i,j-1]) (a[i] <> a[j])

三:采用自底向上法

这里的自底向上和以前的不一样。这里c[i,j]依赖c[i+1,j],说明要先求出c[i+1,j],所以i应该是递减的,即要先求出i=8,才能求出i=7。

四:构造最优解

构造需要最大子序列的首尾,最大子序列包含的字符数。

 

代码如下:

#include <iostream>
using namespace std;
#define max(x,y) ((x)>(y)?(x):(y))

char a[1024];
int c[100][100];
char b[1024];
int k = 0;

void cprint(int m, int n, int q);
int main()
{
    memset(&a, 0, sizeof(a));
    snprintf(a,sizeof(a),"character");
    int alen = strlen(a);
    memset(&c, 0, sizeof(c));
    int q = -1;
    int m = -1;
    int n = -1;
    c[alen][alen] = 1;
    for(int i = alen-1; i>=0; i--)
    {
        for(int j = i; j<=alen; j++)
        {
            if(i == j)
            {
                c[i][j] = 1;
            }
            else if(j < i)
            {
                c[i][j] = 0;
            }
            else if(a[i] == a[j])
            {
                c[i][j] = c[i+1][j-1] + 2;
                if(q < c[i][j])
                {
                    q = c[i][j];
                    m = i;
                    n = j;
                } 
            }
            else
            {
                c[i][j] = max(c[i+1][j],c[i][j-1]);
            }
        }        
    }
    cout<<q<<endl;
    cprint(m,n,q);
    return 0;
}

/*

打印最大回文子序列的函数采用递归的方式,如果a[i] = a[j],则打印a[i],如果不相等,则看是

c[i+1,j]大还是c[i,j-1]大,以此决定改舍弃a[i]还是a[j],然后递归调用打印函数,直到q = 0,说明前一半已经打印完了,再打印后一半,后一半是在打印前一半的时候已经储存了。

*/

void cprint(int m, int n, int q)
{
    if(q == 1)
    {
        cout<<a[m];
        q = 0;
    }
    if(q == 0)
    {
        for(int t = k-1; t>=0; t--)
            cout<<b[t];
        cout<<endl;   
        return;
    }
    if(a[m] == a[n])
    {
        cout<<a[m];
        b[k] = a[m];
        k++;
        q = q-2;
        cprint(m+1,n-1,q);
    }
    else if(c[m][n-1] > c[m+1][n])
    {
        cprint(m,n-1,q);
    }
    else
    {
        cprint(m+1,n,q);
    }
}

posted @ 2013-12-18 22:04  米其林轮船  阅读(347)  评论(0编辑  收藏  举报