UVA11584

题目大意:见刘汝佳《算法竞赛入门经典(第2版)》P275

解题思路:

  有点类似最长上升子序列的一个DP问题。

  设 dp[i] 为对于字符串 s[1,...,i] 的最少回文串数。转移方程为:dp[i] = min{dp[j] + 1 | j<i,s[j+1,...,i]为回文串}。那么问题就是如何判断某个字符串子串是不是回文串。本来DP这部分的时间复杂度就是O(n^2),如果再对于每一个“状态”加上一个O(n)的循环来判断是否为回文数的话,时间复杂度就变成 O(n^3)带入数据范围一算不难发现会超时,那么我们只能预处理判断的这部分。请看程序及注释。

AC代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 const int maxn=1000+3,inf=0x7fffffff;
 8 char inp[maxn];
 9 bool is_pp[maxn][maxn];
10 int dp[maxn];
11 int main()
12 {
13     int n;
14     scanf("%d",&n);
15     while(n--){
16         memset(is_pp,false,sizeof(is_pp));
17         scanf("%s",inp+1);
18         int len=strlen(inp+1);
19 //**************************************************************************
20 //预处理部分
21         for(int i=1;i<=len;i++){    //枚举中点
22             is_pp[i][i]=true;       //单个字符肯定是回文串
23             for(int j=1;;j++){      //向左右伸展
24                 if(i-j<1||i+j>len) break;
25                 if(inp[i-j]==inp[i+j])  is_pp[i-j][i+j]=true;   
26                 else    break;      //一旦发现左右不等,当即退出
27             }
28             if(i+1<=len&&inp[i]==inp[i+1]){//上面一个循环处理的是字符串长度为奇数的部分,这个循环处理的是字符串长度为偶数的部分
29                 is_pp[i][i+1]=true;
30                 for(int j=1;;j++){
31                     if(i-j<1||i+j+1>len)   break;
32                     if(inp[i-j]==inp[i+j+1])    is_pp[i-j][i+j+1]=true;
33                     else    break;
34                 }
35             }
36         }
37 //*************************************************************************
38         dp[0]=0;
39         for(int i=1;i<=len;i++){
40             dp[i]=inf;
41             for(int j=0;j<i;j++){
42                 if(is_pp[j+1][i])
43                     dp[i]=min(dp[i],dp[j]+1);
44             }
45         }
46         printf("%d\n",dp[len]);
47     }
48     return 0;
49 }

 

posted @ 2017-10-11 21:04  Blogggggg  阅读(164)  评论(0编辑  收藏  举报