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.
A 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; } }