题目
思路
1.先进行回文串打表,判断回文串的方法:枚举中心,然后向两边延伸。
2.状态定义:d(i),字符1~i划分成的最小回文串个数。
3.初状态:d[0]=0,d[1..n]=INF。(INF是为了配合状态转移时的max)
4.答案:d[n]
5.状态转移方程:
d(i)=min{d(j)+1|s[j+1...i]是回文串}
d
(
i
)
=
m
i
n
{
d
(
j
)
+
1
|
s
[
j
+
1...
i
]
是
回
文
串
}
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int INF = 1 << 30;
const int maxn = 1000 + 10;
int n, d[maxn], G[maxn][maxn];
char A[maxn];
int main() {
int T;
scanf("%d", &T);
while (T--) {
memset(G, 0, sizeof(G));
scanf("%s", A + 1);
n = strlen(A + 1);
// 回文串的真实打表方法
_rep(i, 1, n) {
for (int a = i, b = i; a >= 1 && b <= n; a--, b++) { // aacaa
if (A[a] == A[b])
G[a][b] = G[b][a] = 1;
else break;
}
for (int a = i, b = i+1; a >= 1 && b <= n; a--, b++) { // acca
if (A[a] == A[b])
G[a][b] = G[b][a] = 1;
else break;
}
}
_rep(i, 1, n) d[i] = INF;
d[0] = 0;
_rep(i, 1, n)
for (int j = i - 1; j >= 0; j--)
if (G[j + 1][i])
d[i] = min(d[i], d[j] + 1);
printf("%d\n", d[n]);
}
return 0;
}
废话
夏天的蚊子是真的恐怖。。。