UVA 11584 或 BNU20002 划分成回文串 DP求一个串最少能划分成多少个文回串

该博客探讨了如何使用动态规划(DP)方法将一个字符串划分为尽可能少的回文子串。通过举例说明了不同类型的字符串,如'racerac'、'fastcar'和'aaadbccb',如何进行有效的回文划分。输入包含测试用例数量及每个用例的字符串,要求输出每个字符串所需的最小回文分组数。
摘要由CSDN通过智能技术生成

Problem H: Partitioning by Palindromes

Can you read upside-down?

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.

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 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.

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
 
 
 
 
//想法1:为每一个i到j的串提前预处理f[i][j]=1则是回文串。这样总的复杂度还是N^2
//然后dp,如果i-j是一个文回串,则dp[i]=min(dp[i],dp[j-1]+1)
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int f[1005][1005],l,dp[1005];
char s[1005];
void init()
{
    memset(f,0,sizeof(f));
    for(int i=1;i<=l;++i){  //中间想向外枚举
        for(int j=0;i-j>0&&i+j<=l&&s[i-j]==s[i+j];++j){//奇数大小的串,是否为回文串
            f[i-j][i+j]=1;
        }
    }
    for(int i=1;i<l;++i){ //中间想向外枚举
        for(int j=0;i-j>0&&i+j+1<=l&&s[i-j]==s[i+j+1];++j){//偶数大小的串,是否为回文串
            f[i-j][i+j+1]=1;
        }
    }
}
void solve()
{
    scanf("%s",s+1);
    l=strlen(s+1);
    init();
    dp[0]=0;  dp[1]=1;
    for(int i=2;i<=l;++i){
        dp[i]=i;
        for(int j=1;j<=i;++j){
            if(f[j][i]){ //i-j回文
                dp[i]=min(dp[i],dp[j-1]+1);
            }
        }
    }
    printf("%d\n",dp[l]);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        solve();
    }
    return 0;
}

//想法2:
//直接dp,如果i-j是一个文回串(这里一个子函数判断),则dp[i]=min(dp[i],dp[j-1]+1)
//按分析,dp需要n^2的复杂度,判断需要n,总计n^3,可是这居然更快,我猜是数据方面应该让判断很快就过去了
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
char str[1005];
int dp[1005];
bool Check(int l, int r)
{
	while (l < r)
	{
		if (str[l] != str[r]) return false;
		l++; r--;
	}
	return true;
}
int main()
{
	int T, i, j;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%s", str + 1);
		int len = strlen(str + 1);
		for (i = 1; i <= len; i++)
		{
			dp[i] = dp[i - 1] + 1;
			for (j = 1; j < i; j++)
				if (Check(j, i)) dp[i]=min(dp[j - 1] + 1, dp[i]);//i-j回文
		}
		printf("%d\n", dp[len]);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值