UVa 10617 Again Palindrome(回文 区间dp)

A palindorme is a sequence of one or more characters that reads the same from the left as it does from the right. For example, Z, TOT and MADAM are palindromes, but ADAM is not.
Given a sequence S of N capital latin letters. How many ways can one score out a few symbols (maybe 0) that the rest of sequence become a palidrome. Varints that are only different by an order of scoring out should be considered the same.
Input
The input file contains several test cases (less than 15). The first line contains an integer T that indicates how many test cases are to follow.
Each of the T lines contains a sequence S (1 ≤ N ≤ 60). So actually each of these lines is a test case.
Output
For each test case output in a single line an integer — the number of ways.
Sample Input
3
BAOBAB
AAAA
ABA

Sample Output
22 15 5

题目大意:
给一个长度《=60的字符串,删去其中一些字符,使之成为回文串。问一共有多少种删法。形如 T ,TOT都是回文串。
思路:
最 朴素的想法:是 先枚举要删的个数x,再枚举出删除x个字符的所有情况,一一判断。显然这样复杂度很高,也不好操作。

于是我们先考虑最简单的情况:
1.只有两个字符。如果这两个字符相等答案就是各自一种情况+组合在一起的一种情况=2+1=3;如果不相等 就只是各自的情况相加=2。
2.再考虑三个字符。形如:ABA 边缘的两个字符相等。 我们可以看成是AB+A ,A+AB,A+B+A。可以发现 当前的要求的结果 是可以利用一个更小的子问题的结果来求解的。
3.多个字符。A+ABCBA+A。
要解决当前的问题,需要利用更小的一个子问题,,,一直分解下去,就会变成最简单的只含一个字符 的问题。于是发现这是一个动归。满足最优子结构。
而影响决策的因素 只有边缘两个字符是否相等。
想到是dp很容易,,但动归方程写的时候要想清楚。
1.s[i]==s[j],此时dp[i][j]=dp[i+1][j] (left)+dp[i][j-1] (right)-dp[i+1][j-1] (中间重复计算部分)+dp[i+1][j-1] (边缘字符都留下会增加的部分)+1(只留下边缘的两个字符);
2.s[i]!=s[j],这时边缘两个字符肯定是无法同时存在的了。所以就只有上一个方程的前一部分dp[i][j]=dp[i+1][j] (left)+dp[i][j-1] (right)-dp[i+1][j-1] (中间重复计算部分);
边缘条件是dp[i][i]=1;答案在dp[0][n-1] 里。

感受:
1.对于不难想到的dp问题 一定要注意转移方程考虑的全面性。。。。
2.数组一定要开longlong。。。

// Created by ZYD in 2015.
// Copyright (c) 2015 ZYD. All rights reserved.
//

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <climits>
#include <string>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define maxn 1000000
#define ll long long
#define mk make_pair
#define pb push_back
#define mem(array) memset(array,0,sizeof(array))
const double EPS=1e-9;
typedef pair<int,int> P;
ll T,dp[100][100];
char s[65];
int main()
{
    freopen("in.txt","r",stdin);
    cin>>T;
    while(T--)
    {
        cin>>s;
        mem(dp);
        int n=strlen(s);
        for(int i=0;i<n;i++) dp[i][i]=1;
        for(int j=1;j<n;j++)
            for(int i=j-1;i>=0;i--)
                if(s[i]==s[j]) dp[i][j]=dp[i+1][j]+dp[i][j-1]+1;
                else dp[i][j]=dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1];       

        cout<<dp[0][n-1]<<endl; 

    }

    return 0;
}


你可能感兴趣的:(uva)