P3625 划分成回文串
时间限制 : 10000 MS 空间限制 : 65536 KB
问题描述
给一个字符串, 要求把它分割成若干个子串,使得每个子串都是回文串。问最少可以分割成多少个。
例如:
“racecar”本身就是回文串,答案为1
“fastcar”,答案为7,分成的7个回文串为"f", "a", "s", "t", "c", "a", "r"
“aaadbccb”,答案为3,分成的3个回文串为"aaa", "d", "bccb"
输入格式
一行,一个由小写字母构成的字符串,该字符串的长度不超过300
输出格式
一行,一个整数,表示最少分割出的回文串的个数。
样例输入
样例输入1:
racecar
样例输入2:
fastcar
样例输入3:
aaadbccb
样例输出
样例输出1:
1
样例输出2:
7
样例输出3:
3
时间限制 : 10000 MS 空间限制 : 65536 KB
问题描述
给一个字符串, 要求把它分割成若干个子串,使得每个子串都是回文串。问最少可以分割成多少个。
例如:
“racecar”本身就是回文串,答案为1
“fastcar”,答案为7,分成的7个回文串为"f", "a", "s", "t", "c", "a", "r"
“aaadbccb”,答案为3,分成的3个回文串为"aaa", "d", "bccb"
输入格式
一行,一个由小写字母构成的字符串,该字符串的长度不超过300
输出格式
一行,一个整数,表示最少分割出的回文串的个数。
样例输入
样例输入1:
racecar
样例输入2:
fastcar
样例输入3:
aaadbccb
样例输出
样例输出1:
1
样例输出2:
7
样例输出3:
3
来源 uva11584
分析:
当然是动规:
f[i]: 从1到i最少能划分成的个数;
(1) 如果i到j是回文串,f[i][j]=1;
(2)
f[i]= min{f[j-1]+1} (s[j]......s[i]是回文串)
1<=i<=n , j from i-1 down to 1;
复杂度O(n^2)
如果mark[i][j]表示i到j是不是回文串, 如何快速的推出 mark数组?
当然是再来一次动规
只有当s[i]==s[j],并且i+1到j-1是回文串时 mark[i][j]=true.
初值:
mark[i][i]=true;
一定要注意还有一个特殊情况: s[i]==s[i+1] => mark[i][i+1]=true;
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=2000+5;
char s[maxn];
int f[maxn];
bool mark[maxn][maxn];
int main(){
int i,j,k,n,t;
scanf("%d",&t);
while(t--){
scanf("%s",s+1);
n=strlen(s+1);
memset(mark,0,sizeof(mark));
memset(f,0,sizeof(f));
for(i=1;i<=n;i++){ //初值
mark[i][i]=true;
if(s[i]==s[i+1])mark[i][i+1]=true;
}
for(i=n;i>0;i--) //动规求mark
for(j=i+1;j<=n;j++)
if(s[i]==s[j]&&mark[i+1][j-1])
mark[i][j]=true;
for(i=1;i<=n;i++){ //
f[i]=i;
for(j=i;j>0;j--)
if(mark[j][i])f[i]=min(f[i],f[j-1]+1);
}
cout<<f[n]<<endl;
}
return 0;
}