简介:
给出一个字符串,划分成尽量少的回文串
分析:
根据常识来说,dp状态的设计应该是这样的:
f[i]表示到i位为止,最少能划分为几个回文串
f[i]=min{f[j]+1(j+1~i是回文串)}
显然我们是没办法直接n^2转移的
如果我们在转移的时候O(n)判断(j+1~i)是不是回文串又很浪费时间
所以只能选择预处理,如果我们能够预处理出能够构成回文串的区间,那么问题就可以在n^2的时间内完成
那么怎么预处理呢?
for (int i=0;i<strlen(s);i++)
{
hw[i][i]=1;
if (i!=0&&s[i]==s[i-1]) hw[i-1][i]=1;
for (int j=i-2;j>=0;j--)
if (s[i]==s[j])
hw[j][i]=hw[j+1][i-1];
}
tip
注意在转移的时候,边界的处理
if (hw[0][i]) f[i]=1;
如果0~i位是一个回文串,那么f[i]=1
//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
char s[1003];
int f[1003];
bool hw[1003][1003];
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%s",&s);
memset(f,0x33,sizeof(f));
memset(hw,0,sizeof(hw));
for (int i=0;i<strlen(s);i++)
{
hw[i][i]=1;
if (i!=0&&s[i]==s[i-1]) hw[i-1][i]=1;
for (int j=i-2;j>=0;j--)
if (s[i]==s[j])
hw[j][i]=hw[j+1][i-1];
}
f[0]=1;
for (int i=1;i<strlen(s);i++)
{
if (hw[0][i]) f[i]=1;
for (int j=0;j<i;j++)
if (hw[j+1][i])
f[i]=min(f[i],f[j]+1);
}
printf("%d\n",f[strlen(s)-1]);
}
return 0;
}