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;
}
posted on 2012-04-26 22:37  BFP  阅读(552)  评论(0编辑  收藏  举报