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
原文地址:https://www.cnblogs.com/chenyg32/p/3135609.html