51nod 1154 回文串划分 Manacher+dp

11 篇文章 0 订阅
基准时间限制: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 ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值