划分成回文串
题目大意: 给一个字符串, 要求把它分割成若干个子串,使得每个子串都是回文串。问最少可以分割成多少个。 字符串长度不超过1000。
例如:
“racecar”本身就是回文串,答案为1
“fastcar”,答案为7,分成的7个回文串为"f", "a", "s", "t", "c", "a", "r"
“aaadbccb”,答案为3,分成的3个回文串为"aaa", "d", "bccb"
样例输入1:
racecar
样例输入2:
fastcar
样例输入3:
aaadbccb
样例输出
样例输出1:
1
样例输出2:
7
样例输出3:
3
dp[i] 为字符串中 1~i 划分成最少回文串的个数。则:
dp[ i ]=min{ dp[ j ] + 1 } 其中,s[ j+1 -> i ] 为回文串
但是如果每次判断 s[ j+1 -> i ] 是否为回文串,那么时间复杂度为O(n3),显然不够优秀。
所以,应先O(n2)预处理出所有s[ i -> j ]是否为回文串(分长度为奇数和长度为偶数)。
总复杂度:O(n2)
#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define ll long long const int maxn=1000+10; char a[maxn]; int dp[maxn],l,lef,rig; bool p[maxn][maxn]; template<typename T>void read(T& aa) { char cc; ll ff;aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int main(){ memset(dp,127,sizeof(dp)); memset(p,false,sizeof(p)); scanf("%s",a+1); l=strlen(a+1); for(int i=1;i<=l;i++){ lef=i;rig=i; while(lef>0&&rig<=l){ if(a[lef]==a[rig]) p[lef][rig]=true; else break; lef--;rig++; } } for(int i=1;i<l;i++){ lef=i;rig=i+1; while(lef>0&&rig<=l){ if(a[lef]==a[rig]) p[lef][rig]=true; else break; lef--;rig++; } } dp[1]=1;dp[0]=0; for(int i=2;i<=l;i++) for(int j=0;j<i;j++){ if(p[j+1][i]) dp[i]=min(dp[i],dp[j]+1); } cout<<dp[l]<<endl; return 0; }