8633 回文划分

8633 回文划分

该题有题解

时间限制:1000MS  内存限制:1000K
提交次数:169 通过次数:63

题型: 编程题   语言: C++;C

Description

    我们说一个字符串是回文串,那么意味着这个串从两边读起来的字母都是一样的。例如racecar是回文串,
然而fastcar则不是。
    对一个串的划分意思是将一个串划分为若干个部分。例如,racecar可以划分为race 和car两部分。给出
一个串,要把这个串划分为若干个回文串,那么至少要把这个串划分为多少部分?
例如
'racecar'已经是回文串,划分为1 个部分即可(这个部分就是racecar)。
'fastcar' 需要被划分为七个部分 ('f', 'a', 's', 't', 'c', 'a', 'r')。根据回文串的定义,单个字母也是回文串。
'aaadbccb' 分成可以被分为三个回文串 ('aaa', 'd', 'bccb')。找不到更少的划分方法。



输入格式

输入的第一行是数字T,表示输入文件含有T个CASE。之后有T行,每行有一个长度不大于1000的字
符串,全部由小写字母组成,中间没有空格。


输出格式

对于每个CASE,输出一个数字,表示对该字符串的回文串最小划分。


输入样例

3
racecar
fastcar
aaadbccb


输出样例

1
7
3


提示



来源

PKKJ @ 07 GIS 1

作者

admin


思路

这是一道在字符串上进行分割的动态规划问题。对于动态规划,我们首先要确定什么是状态。这里,一般的状态表示方法如下:dp[i]表示将前i个字符组成的字串进行划分,能够最少划分多少个串,每个串都是回文串。确定状态之后,我们可以确定状态转移方程:dp[i]=min(dp[j]+1,j<i&&j+1~i是一个回文串)。判断回文串可以在O(n)内解决,整体时间复杂度为i*j*判断回文串=O(n3)。

要求dp[i]我们可以先把dp[i-1]+1赋值个它,这是默认它不与前面的字符形成回文串的情况,如果它与前面的一段字符能形成回文串,则可能取到更小的划分。现在我们要去找回文串尝试找更小划分。判断第k~i(0<k<=i)的字符串是否为回文串,如果是,则判断dp[i]是否大于dp[k-1]+1。如果大于,说明当前dp[i]记录的划分次数还不是最小的,至少dp[k-1]+1是比它小的,因此把dp[k-1]+1赋值给它,增加k值循环求出最小的dp[i]。继续求出dp[i+1],dp[i+2]......求到的最后一个dp[end]即为整个字符串的回文串最小划分。为了方便,dp[0]不存储划分次数,但它的作用是为dp[1]提供参考,因此设为0。

例如:aba字符串

1》 dp[0]=0;

2》子串a的最小划分: dp[1]=dp[0]+1==1;k==1;i==1,第k到i的字符串即a本身,是回文串,但dp[1]!>dp[k-1]==dp[0],不做处理,即dp[1]==1;

3》子串ab的最小划分: dp[2]=dp[1]+1==2;i==2;k为1时第k~i的字符串不是回文串;k为2时第k~i的字符串取到b本身,是回文串,但dp[2]!>dp[k-1]==dp[1],不做处理,即dp[2]==2;

4》子串aba的最小划分:dp[3]=dp[2]+1==3;i==3;k为1时第k~i的字符串是回文串,且dp[3]>dp[k-1]==dp[0],因此dp[3]=dp[0]+1==1;k为2时第k~i的字符串不是回文串;k为3时第k~i的字符串是a本身,是回文串,但dp[3]!>dp[k-1]==dp[2],不做处理,即dp[3]==1;

现在aba字符串回文最小划分出来了,即dp[3]==1;

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 1010
char str[SIZE];
int dp[SIZE];
int isPalindrome(int startIndex,int endIndex){
    for(;startIndex<endIndex;startIndex++,endIndex--){
        if(str[startIndex]!=str[endIndex]) return 0;
    }
    return 1;
}
int main()
{
   int T,index,index1;
   scanf("%d",&T);
   while(T--){
    scanf("%s",str);
    dp[0]=0;
    for(index=0;index<strlen(str);index++){
        dp[index+1]=dp[index]+1;
        for(index1=0;index1<index;index1++){
            if(isPalindrome(index1,index)) {
                 //循环将到当前位置的划分次数与匹配到的回文串的开始位置前一个位置的划分次数加一对比。从而保证当前位置取到最小划分次数。
                if(dp[index+1]>dp[index1]+1){
                    dp[index+1]=dp[index1]+1;
                }
            }
        }
    }
    printf("%d\n",dp[strlen(str)]);
   }
}


  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值