Uva 11584 - Partitioning by Palindromes(预处理+DP)

题目链接 https://cn.vjudge.net/problem/UVA-11584

【题意】
输入一个由小写字母组成的字符串,你的任务是把它们划分成尽量少的回文串。比aaadbccb至少要划分成3个回文串,aaa,d,bccb 字符串长度不超过1000

【思路】
设dp(i)表示字符串s[0]到s[i]的子串可以划分成回文串的最少个数,那么状态转移方程为dp(i)=min{dp(j)+1 | s[j+1]~s[i]是回文串} 在递推求解之前需要先预处理出原字符串s[i]~s[j]是否为回文串,可以枚举每个字符和每两个字符为中点,然后向两边延伸,复杂度是O(n^2),之后递推的过程复杂度也是O(n^2),总的时间复杂度也就为O(n^2)

#include<bits/stdc++.h>
using namespace std;

const int inf=2e9;
const int maxn=1050;

int len;
char s[maxn];
int dp[maxn];
bool ok[maxn][maxn];

void judge(){
    memset(ok,0,sizeof(ok));
    for(int i=0;i<len;++i){//枚举每个s[i]作为中心的子串是否是回文串 
        ok[i][i]=true;
        for(int j=1;;++j){
            int p=i-j;
            int q=i+j;
            if(p<0||q>=len) break;
            if(s[p]==s[q]) ok[p][q]=true;
            else break;
        }
    }
    for(int i=0;i<len-1;++i){//枚举每个s[i]和s[i+1]作为中心的子串是否是回文串 
        if(s[i]!=s[i+1]) continue;
        ok[i][i+1]=true;
        for(int j=1;;++j){
            int p=i-j;
            int q=i+1+j;
            if(p<0||q>=len) break;
            if(s[p]==s[q]) ok[p][q]=true;
            else break;
        }
    }
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%s",s);
        len=strlen(s);
        judge();
        dp[0]=1;
        for(int i=1;i<len;++i){
            if(ok[0][i]) {
                dp[i]=1;
                continue;
            }
            int ans=inf;
            for(int j=0;j<i;++j){
                if(ok[j+1][i]) ans=min(ans,dp[j]+1);
            }
            dp[i]=ans;
        }
        printf("%d\n",dp[len-1]);
    }
    return 0;
}
posted @ 2018-03-27 19:21  不想吃WA的咸鱼  阅读(115)  评论(0编辑  收藏  举报