zoukankan      html  css  js  c++  java
  • 动态规划解最大回文子序列

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

    例如字符串 "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);
        }
    }

  • 相关阅读:
    Struts2【UI标签、数据回显、资源国际化】
    Struts2【配置】知识要点
    Struts2与Spring整合
    Struts2入门这一篇就够了
    Hibernate最全面试题
    Hibernate【查询、连接池、逆向工程】
    Hibernate【缓存】知识要点
    Hibernate【inverse和cascade属性】知识要点
    输入法设置,SublimeTest,putty掉线
    Hibernate【映射】知识要点
  • 原文地址:https://www.cnblogs.com/johnsblog/p/3481151.html
Copyright © 2011-2022 走看看