基准时间限制:1 秒 空间限制:131072 KB 分值: 40
难度:4级算法题
有一个字符串S,求S最少可以被划分为多少个回文串。
例如:abbaabaa,有多种划分方式。
a|bb|aabaa - 3 个回文串
a|bb|a|aba|a - 5 个回文串
a|b|b|a|a|b|a|a - 8 个回文串
其中第1种划分方式的划分数量最少。
Input
输入字符串S(S的长度<= 5000)。
Output
输出最少的划分数量。
Input示例
abbaabaa
Output示例
3
思路:dp[i] 表示到i所能够划分的最少回文串数量。
dp[i] = min( dp[i] , dp[j-1]+1); ( 当j-i是回文串时 )。
先用Manacher算法预处理一下得到P[i]数组,进行dp时,取i,j中间的位置的p【pos】值,如果p[pos]+pos >= i 或者j==i,那么说明j-i这一段是回文。
(Manacher算法p[i]+i-1为每个回文中心最右所能达到的位置,这个位置为'#'号。)
Code:
#include <bits/stdc++.h>
using namespace std;
const int AX = 1e4+66;
int p[AX];
int dp[AX];
char s[AX];
int main(){
cin >> s ;
int len = strlen(s);
for( int i = len ; i >= 0 ; i-- ){
s[2*i+2] = s[i];
s[2*i+1] = '#';
}
s[0] = '$';
int id = 0 , mx = 0 ;
for( int i = 2 ; i < 2 * len + 1 ; i++ ){
if( p[id] + id > i ){
p[i] = min( p[id] + id - i , p[2*id-i] );
}else p[i] = 1;
while( s[i - p[i]] == s[i+p[i]] ) p[i] ++;
if( mx < p[i] + i ){
mx = p[i] + i;
id = i;
}
}
dp[0] = 1;
for( int i = 1 ; i < len ; i++ ){
dp[i] = i + 1 ;
for( int j = 0 ; j <= i ; j++ ){
int tm_i = 2 * i + 2 ;
int tm_j = 2 * j + 2 ;
int pos = ( tm_i + tm_j ) >> 1 ;
if( p[pos] + pos - 1 > tm_i || i == j ){
dp[i] = min( dp[i] , dp[j-1] + 1 );
}
}
}
cout << dp[len-1] << endl;
return 0 ;
}