Partitioning by Palindromes

We say a sequence of characters is a palindrome if it is the same written forwards and backwards. For example, 'racecar' is a palindrome, but 'fastcar' is not.

partition of a sequence of characters is a list of one or more disjoint non-empty groups of consecutive characters whose concatenation yields the initial sequence. For example, ('race', 'car') is a partition of 'racecar' into two groups.

Given a sequence of characters, we can always create a partition of these characters such that each group in the partition is a palindrome! Given this observation it is natural to ask: what is the minimum number of groups needed for a given string such that every group is a palindrome?

For example:

  • 'racecar' is already a palindrome, therefore it can be partitioned into one group.
  • 'fastcar' does not contain any non-trivial palindromes, so it must be partitioned as ('f', 'a', 's', 't', 'c', 'a', 'r').
  • 'aaadbccb' can be partitioned as ('aaa', 'd', 'bccb').

Input begins with the number n of test cases. Each test case consists of a single line of between 1 and 1000 lowercase letters, with no whitespace within.

For each test case, output a line containing the minimum number of groups required to partition the input into groups of palindromes.

Sample Input

3

racecar

fastcar

aaadbccb

Sample Output

1

7

3

题意:把字符串划分成尽量少的回文串。

p[i]表示从i开始的最长回文字符串的长度
dp[i]表示从i开始的最小回文串数目,dp[0]即为所求

       r  a c  e c a r
p[]   7 5 3 1 1 1 1 1 (p[]的最后一位冗余)

dp[] 1 2 3 4 3 2 1 0 (dp[]的最后一位是为了方便计算dp,模拟一下过程就知道了)

    f a  s t c  a r
p[]   1 1 1 1 1 1 1 1

dp[] 7 6 5 4 3 2 1 0

    a a a d b  c c b
p[]   3 2 1 1 4 2 1 1 1

dp[] 3 3 3 2 1 2 2 1 0

dp[]从后往前刷,因为p[i]都是与它后面的元素相关联,所以应当先求后面的元素才能求前面的
关于更新dp,对于每一位,可以把它当成一个回文字符串,或者把它当成一个更长的回文字符串(i to i+p[i]-1)
所以 dp[i] = min(dp[i+p[i]]+1, dp[i+1]+1);

 

#include <iostream>

#include <string>

using namespace std;



string s;



//从l到r是不是回文?

bool palindromes(int l, int r)

{

    for (int i = l, j = r; i < j; ++i,--j)

    {

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

            return false;

    }

    

    return true;

}



int main()

{

    int m;

    

    cin >> m;

    

    while (m--)

    {

        cin >> s;

        

        int size = s.size()+1;

        

        int p[size],dp[size];    //p[i]表示从i开始的最长回文字符串的长度 

                                //dp[i]表示从i开始的最小回文串数目,dp[0]即为所求 

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

            p[i] = 1, dp[i] = 0; 

            

        for (int i = 0; i < s.size(); ++i)    //p[]从前往后刷

            for (int j = 1; i+j < s.size();++j)

                if (palindromes(i, i+j))

                    p[i] = j+1;

        

        for (int i = size-2; i >= 0; --i)    //dp[]从后往前刷

            dp[i] = min(dp[i+p[i]]+1, dp[i+1]+1);

        

        cout << dp[0] << endl;

    }

}
View Code

 

你可能感兴趣的:(partition)