题目链接 https://cn.vjudge.net/problem/UVA-11584
【题意】
输入一个由小写字母组成的字符串,你的任务是把它们划分成尽量少的回文串。比aaadbccb至少要划分成3个回文串,aaa,d,bccb 字符串长度不超过1000
【思路】
设dp(i)表示字符串s[0]到s[i]的子串可以划分成回文串的最少个数,那么状态转移方程为dp(i)=min{dp(j)+1 | s[j+1]~s[i]是回文串} 在递推求解之前需要先预处理出原字符串s[i]~s[j]是否为回文串,可以枚举每个字符和每两个字符为中点,然后向两边延伸,复杂度是O(n^2),之后递推的过程复杂度也是O(n^2),总的时间复杂度也就为O(n^2)
#include<bits/stdc++.h>
using namespace std;
const int inf=2e9;
const int maxn=1050;
int len;
char s[maxn];
int dp[maxn];
bool ok[maxn][maxn];
void judge(){
memset(ok,0,sizeof(ok));
for(int i=0;i<len;++i){//枚举每个s[i]作为中心的子串是否是回文串
ok[i][i]=true;
for(int j=1;;++j){
int p=i-j;
int q=i+j;
if(p<0||q>=len) break;
if(s[p]==s[q]) ok[p][q]=true;
else break;
}
}
for(int i=0;i<len-1;++i){//枚举每个s[i]和s[i+1]作为中心的子串是否是回文串
if(s[i]!=s[i+1]) continue;
ok[i][i+1]=true;
for(int j=1;;++j){
int p=i-j;
int q=i+1+j;
if(p<0||q>=len) break;
if(s[p]==s[q]) ok[p][q]=true;
else break;
}
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%s",s);
len=strlen(s);
judge();
dp[0]=1;
for(int i=1;i<len;++i){
if(ok[0][i]) {
dp[i]=1;
continue;
}
int ans=inf;
for(int j=0;j<i;++j){
if(ok[j+1][i]) ans=min(ans,dp[j]+1);
}
dp[i]=ans;
}
printf("%d\n",dp[len-1]);
}
return 0;
}