UVA 10617 - Again Palindrome

来源:互联网 发布:洗车哪个软件好 编辑:程序博客网 时间:2024/06/07 18:01

这道题因为那个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 65long 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;}
0 0
原创粉丝点击