点下看看能不能打开:https://vjudge.net/problem/34398/origin
题目大意:输入小写字母字符串,然后分割成尽量少的回文串,例如:recacer本身就是回文串,fastcar只能分成7个,aaadbccb最少为3个为:aaa d bccb
ps:紫书p275
ps:记得以前做过关于回文串的dp,那个是比较复杂的了,属于区间dp的。
对于这个题的话,要求最少的回文串,那么就记录dp[j]表示前j个字符所能分割的最少回文串。那么如果出现i在j的后面,如果j+1~i是回文的话,那么就要比较dp[i]和dp[j]+1的大小去min;j是从0-i的
这里有一个预处理求区间[i,j]是否回文串的,详细见代码。为了方便处理,字符串从1开始的。
#include <iostream>
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
char s[1111];
int dp[1111];
int vis[1111][1111];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",s+1);
int n=strlen(s+1);
memset(vis,0,sizeof(vis));
memset(dp,INF,sizeof(dp));///最大化
for(int k=1;k<=n;k++)
{
int i,j;
i=k;
j=k;
while(i>0&&j<=n)
{
if(s[i]==s[j])
{
vis[i][j]=1;
i--;
j++;
}
else break;
}
i=k;
j=k+1;
while(i>0&&j<=n)
{
if(s[i]==s[j])
{
vis[i][j]=1;
i--;
j++;
}
else break;
}
}
dp[0]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<i;j++)
{
if(vis[j+1][i])
{
dp[i]=min(dp[i],dp[j]+1);
}
}
}
printf("%d\n",dp[n]);
}
return 0;
}