UVA 11584 Partitioning by Palindromes 划分回文串 (Manacher算法)
d[i]表示前面i个字符划分成的最小回文串个数,
转移:当第i字符加进来和前面区间j构成回文串,那么d[i] = d[j]+1。
要判断前面的字符j+1到i是不是回文串,可以用Manacher算法预处理出来。(其实O(n^2)判断回文串的也可以,时间复杂度不会变,只是为了学习Manacher
Manacher最奇妙的地方在于用'#'把奇偶串的问题合并到了一起以及利用对称性快速计算P数组
#include <iostream> #include <algorithm> #include <cstring> #include<cstdio> using namespace std; const int MAX = 1042; int len, p[2*MAX]; char str[MAX], newstr[2*MAX]; bool isPal[MAX][MAX]; void change() { int i; newstr[0] = '@'; newstr[1] = '#'; for (i = 0; i < len; i++){ newstr[2*i + 2] = str[i]; newstr[2*i + 3] = '#'; } newstr[2*len + 2] = '\0'; return ; } #define toPre(x) ((x-1)>>1) void Manacher() { int i, j, id, maxid = 0; len = 2 * len + 2; for (i = 0; i < len; i++){ if (maxid > i){ p[i] = min(p[2*id - i], maxid - i);//利用对称性快速计算p数组 } else{ p[i] = 1; } while (newstr[i+p[i]] == newstr[i-p[i]]) p[i]++; if (p[i] + i > maxid){ maxid = p[i] + i; id = i; } } for( i = 1; i < len; i++){ char pivot = newstr[i]; p[i]--; for(j = !(pivot<='z'&&pivot>='a'); j < p[i]; j+=2){ int u = toPre(i-j),v = toPre(i+j); isPal[u][v] = true; } } } int d[MAX]; int main() { //freopen("in.txt","r",stdin); int T; scanf("%d",&T); while (T--){ scanf("%s",str); len = strlen(str); change(); memset(isPal,0,sizeof(isPal)); Manacher(); len = (len-1)>>1; for(int i = 0; i < len; i++){ d[i] = isPal[0][i]?1:i+1; for(int j = 0; j < i; j++)if(isPal[j+1][i]){ d[i] = min(d[i],d[j]+1); } } printf("%d\n",d[len-1]); } // system("pause"); return 0; }