Partitioning by Palindromes (dp找回文串最少个数)

本文探讨了如何将一个字符串分割成最少数量的回文子串的问题,并提供了一种使用动态规划解决该问题的方法。通过枚举每一段子串判断其是否为回文串,并利用状态转移方程来更新最小分割数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

We say a sequence of characters
is a palindrome if it
is the same written forwards
and backwards. For example,
‘racecar’ is a palindrome, but
‘fastcar’ is not.
A partition of a sequence of
characters is a list of one or
more disjoint non-empty groups
of consecutive characters whose
concatenation yields the initial
sequence. For example, (‘race’,
‘car’) is a partition of ‘racecar’
into two groups.
Given a sequence of characters,
we can always create a partition
of these characters such
that each group in the partition
is a palindrome! Given this observation
it is natural to ask:
what is the minimum number of
groups needed for a given string
such that every group is a palindrome?
For example:
• ‘racecar’ is already a
palindrome, therefore it
can be partitioned into
one group.
• ‘fastcar’ does not contain
any non-trivial palindromes,
so it must be partitioned
as (‘f’, ‘a’, ‘s’, ‘t’,
‘c’, ‘a’, ‘r’).
• ‘aaadbccb’ can be partitioned
as (‘aaa’, ‘d’, ‘bccb’).
Input
Input begins with the number n of test cases. Each test case consists of a single line of between 1 and
1000 lowercase letters, with no whitespace within.
Output
For each test case, output a line containing the minimum number of groups required to partition the
input into groups of palindromes.




Sample Input
3
racecar
fastcar
aaadbccb
Sample Output
1
7

3

这道题就是找回文串的最少个数。

dp【i】表示从1位置到i位置的最小回文个数。

方法是两层for循环依次找一遍。就是枚举每一小段(位置j->i)然后看这一段是否是一个回文子串。如果是的话,那么就要考虑状态转移方程,看前j-1个组成的min回文串+(一个j->i回文串)的num跟原来dp【i】比较取小的。状态方程就出来了。

前边我对h  insert了第一个字符,目的是这样第一个字母就是从1开始,方便写。

代码:

#include<bits/stdc++.h>
using namespace std;
string h;
int dp[30000];
int judge(int a, int b)
{
    while (a <= b && h[a] == h[b])
        ++a, --b;
    return a >= b;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        cin>>h;
        h.insert(0,"a");
        //cout<<h<<endl;
        memset(dp,0x3f,sizeof(dp));
        dp[0]=0;
        dp[1]=1;
        for(int i=1;i<h.length();i++)
        {
            for(int j=1;j<=i;j++)
            {
                if(judge(j,i)==1)
                {
                    dp[i]=min(dp[i],dp[j-1]+1);
                    //cout<<"j:   "<<j<<"    i:"<<i<<"   "<<dp[i]<<"***"<<endl;
                }
            }
        }
        cout<<dp[h.length()-1]<<endl;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值