UVA 10617 - Again Palindrome

这道题因为那个score out给我蒙住了,其实说白了,就是给你一串字符串,让你从中找出有多少回文字串,这个回文字串可以是一个字母,也可以是多个。

既然是动态规划题:我们肯定要这样想,让我们求长度为len的字符串有多少回文字串,那么长度为len-1的字符串有多少回文子串呢,如果我们求出了len-1的字符串,那么长度为len的字符串的回文字串的个数可不可以通过这个来求出呢,那么长度为len-1的母串可不可以通过len-2的母串求出呢,。。。。。

当然上面的过程当然是可以的:

接下来想一个串如果两端不等的话(ABBO):
那么它的方式就等于 1 + ABB里面的种数 + BBO里面的种数 – 两个集合重复的部分

如果两端相等的话(ABOA):
那么它的方式就等于 1 + ABO里面的种数 + BOA里面的种数 + BO里面的种数(因为BO里面的每种回文在两边同时加上相等的字符还会是回文“B”、“O”—> “ABA”、“AOA”) + 1(两个端点也可以组成一个回文) – 前两个加数里重复的部分。

所以状态转移方程就可以初步定型 :
d[i][j]=d[i][j-1]+d[i+1][j]-temp(如果s[i]==s[j])
d[i][j]=d[i][j-1]+d[i+1][j]+d[i+1][j-1]+1-temp(如果s[i]!=s[j])
上面两式中的temp 表示d[i][j-1]和d[i+1][j]这么多中方法中重复的种数

代码如下:

#include<stdio.h>

#include<string.h>

#define MAXN 65

long long b[MAXN][MAXN];

char s[MAXN];

int n;

void solve()

{

    int len = strlen(s);

    for(int i = 0; i < len; i ++)

    b[i][i] = 1;

    for(int i = 1; i < len; i ++)

        for(int j = 0; i+j < len; j ++)

        {

            long long t;

            if(s[j] != s[i+j]) 

            {

                if(i+j-1 < j+1) t = 0;

                else t = b[j+1][i+j-1];

                b[j][i+j] = b[j][i+j-1] + b[j+1][i+j] - t;

            }

            else

            {

                b[j][i+j] = b[j][i+j-1] + b[j+1][i+j] + 1;

            }

        }

    printf("%lld\n",b[0][len-1]);

}

void input()

{

    while(~scanf("%d",&n))

    while(n --)

    {

        scanf("%s",s);

        solve();

    }

}

int main()

{

    input();

    return 0;

}

你可能感兴趣的:(ROM)