UVA 11584 "Partitioning by Palindromes"(DP+Manacher)
•题意
•思路一
定义 dp[i] 表示 0~i 的最少划分数;
首先,用马拉车算法求解出回文半径数组;
对于第 i 个字符 si,遍历 j (0 ≤ j < i),判断以 j 为回文中心的最大回文串是否包含 si;
如果包含,dp[ i ]=min{dp[ i ],dp[2*j-i-1]+1};
•Code
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e3+50; 4 5 char t[maxn]; 6 int r[maxn<<1]; 7 8 struct Manacher 9 { 10 char s[maxn<<1]; 11 void Init(char *ss,int len) 12 { 13 int index=0; 14 s[index++]='#'; 15 for(int i=0;i < len;++i) 16 { 17 s[index++]=ss[i]; 18 s[index++]='#'; 19 } 20 s[index]='\0'; 21 } 22 void mana(char *ss) 23 { 24 Init(ss,strlen(ss)); 25 int len=strlen(s); 26 int R=-1; 27 int C; 28 for(int i=0;i < len;++i) 29 { 30 r[i]=R > i ? min(R-i+1,r[2*C-i]):1; 31 for(;i-r[i] >= 0 && i+r[i] < len && s[i-r[i]] == s[i+r[i]];r[i]++); 32 if(i+r[i] > R) 33 { 34 R=i+r[i]-1; 35 C=i; 36 } 37 } 38 } 39 }_mana; 40 41 int dp[maxn]; 42 int Solve() 43 { 44 _mana.mana(t); 45 46 dp[0]=1; 47 int len=strlen(t); 48 for(int i=1;i < len;++i) 49 { 50 dp[i]=dp[i-1]+1; 51 for(int j=0;j <= 2*i;++j) 52 { 53 54 ///t中的第i个字符在预处理后的s数组中的位置为2*i+1 55 ///因为可能由偶回文的情况,所以需要用到'#' 56 ///直接判断在s数组中j的对应的最大回文j+r[j]是否包含2*i+1 57 ///如果包含,再找到2*i+1以j为中心的对称点2*j-(2*i+1) 58 ///判断2*j-(2*i+1)对应于t中的位置的前一个位置(2*j-(2*i+1))/2-1是否在[0,len-1]范围内 59 ///如果在,更新dp[i] 60 int cur=j+r[j]; 61 int index=(2*j-2*i-1)/2-1; 62 if(2*i+1 < cur) 63 dp[i]=min(dp[i],1+(index >= 0 ? dp[index]:0)); 64 } 65 } 66 return dp[len-1]; 67 } 68 int main() 69 { 70 // freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin); 71 int test; 72 scanf("%d",&test); 73 while(test--) 74 { 75 scanf("%s",t); 76 printf("%d\n",Solve()); 77 } 78 return 0; 79 }
•思路二(reference from zishu)
定义dp[ i ]表示0~i划分成的最小回文串的个数,则dp[ i ]=min{d[ j ]+1 | j ≤ i && t[ j+1,....,i ]为回文串};
•code
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e3+50; 4 5 char t[maxn]; 6 char s[maxn<<1]; 7 bool isPal[maxn][maxn]; 8 int dp[maxn]; 9 10 void Init()///O(n^2)预处理出t[i,..,j]是否为回文串 11 { 12 int len=strlen(t); 13 for(int i=0;i < len;++i) 14 for(int j=0;j < len;++j) 15 isPal[i][j]=false; 16 int index=0; 17 s[index++]='#'; 18 for(int i=0;i < len;++i) 19 { 20 s[index++]=t[i]; 21 s[index++]='#'; 22 } 23 s[index]='\0'; 24 25 for(int i=0;i < index;++i) 26 { 27 int r=0; 28 while(i-r >= 0 && i+r < index && s[i-r] == s[i+r]) 29 { 30 if((i-r)&1) 31 isPal[(i-r)/2][(i+r)/2]=true; 32 r++; 33 } 34 } 35 } 36 37 int Solve() 38 { 39 Init(); 40 int len=strlen(t); 41 dp[0]=1; 42 for(int i=1;i < len;i++) 43 { 44 dp[i]=dp[i-1]+1; 45 for(int j=0;j < i;++j) 46 if(isPal[j][i]) 47 dp[i]=min(dp[i],1+(j > 0 ? dp[j-1]:0)); 48 } 49 return dp[len-1]; 50 } 51 int main() 52 { 53 // freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin); 54 int test; 55 scanf("%d",&test); 56 while(test--) 57 { 58 scanf("%s",t); 59 printf("%d\n",Solve()); 60 } 61 return 0; 62 }