1. 程式人生 > >【UVa11584】劃分成回文串

【UVa11584】劃分成回文串

回文串 優秀 nbsp als template 都是 else rac bool

題目描述

給一個字符串, 要求把它分割成若幹個子串,使得每個子串都是回文串。問最少可以分割成多少個。 字符串長度不超過1000。
例如:
“racecar”本身就是回文串,答案為1
“fastcar”,答案為7,分成的7個回文串為"f", "a", "s", "t", "c", "a", "r"
“aaadbccb”,答案為3,分成的3個回文串為"aaa", "d", "bccb"


輸入

第一行一個數T。接下來T行,每行一個字符串。


輸出

對於每個字符串輸出答案。


樣例輸入

3

racecar

fastcar

aaadbccb


樣例輸出

1

7

3



題解

dp[i] 為字符串中 1~i 劃分成最少回文串的個數。則:

            dp[ i ]=min( dp[ j ] + 1 ) 其中,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; }

【UVa11584】劃分成回文串