UVA-11584:Partitioning by Palindromes(基础DP)

今天带来一个简单的线性结构上的DP,与上次的照明系统(UVA11400)是同一种类型题,便于大家类比、总结、理解,但难度上降低了。

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!

正序倒序写都相同的字符串我们称之为回文串。例如,‘racecar’就是回文的,‘fastcar’就不是。对一个字符序列的划分即:分成一堆(至少一个)非空不相交的连续字符串,使它们连起来就是原来的字符序列。例如,‘race’,‘car’就是把‘racecar’划分成两组。给定一个字符串,我们总能找到一种划分使得每个子串都是回文串!(大不了一个字母算一个子串)

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

求:使得每个子串都是回文串的最小划分组数。

例如,‘racecar’本身就是个回文串所以它的答案是1组;‘fastcar’不含回文子串,只能一个字母一个字母地分,答案为7组;‘aaadbccb’最优可以分成‘aaa’,‘d’,‘bccb’3组。

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

最先输入测试组数n。每组给出一个长度1~1000的小写字母串,中间没有空格。

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

思路:

假如我遍历一遍字符串 ----> 强如‘fastcar’的话只能一个字母一个字母地苦逼+1,那么有回文子串时,差异是如何产生的呢? ----> 就说racecar吧。走到race的时候还是+1模式,再走一步到c的时候发现跟前面的ce能凑个cec ----> 我们用dp数组表示结果,dp[racec]本来等于dp[race]+1,由于找到了回文子串cec,所以变成了min( dp[race]+1, dp[ra]+1 ) ----> 由于我们不知道当前字母最早可以伸展到哪里去跟别人结合为回文子串,所以可以暴力扫一遍前面的 ----> 至于回文串,一边扫一遍判断也可以,预处理也可以,关键是复杂度。预处理可以枚举回文串中心然后向左右伸展得到(j,i)是不是回文串,可以以n2的复杂度求解,这样dp的过程也是n2。一边dp一边判断大概是n3的复杂度,我不知道怎么就过了我复杂度算错了?……

最开始瞎写的代码1:20ms

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6
 7 int T;
 8 int dp[1001];
 9 char str[1001];
10
11 bool ispalindrome(int start, int end)
12 {
13     for (int i = start; i < (start+end+1)/2; i++)
14         if (str[i] != str[start+end-i])
15             return false;
16     return true;
17 }
18
19 int main()
20 {
21     scanf("%d", &T);
22     while (T--)
23     {
24         scanf("%s", str+1);
25
26         int len = strlen(str+1);
27         for (int i = 1; i <= len; i++)
28         {
29             dp[i] = dp[i-1] + 1;
30             for (int j = 1; j <= i-1; j++)
31                 if (ispalindrome(j, i))//[j,i]是不是回文
32                     dp[i] = min(dp[i], dp[j-1] + 1);
33         }
34
35         printf("%d\n", dp[len]);
36     }
37 }

按照上面瞎改的代码2:20ms

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6
 7 int T;
 8 int dp[1001];
 9 char str[1001];
10 bool ispalindrome[1001][1001];
11
12 int main()
13 {
14     scanf("%d", &T);
15     while (T--)
16     {
17         scanf("%s", str+1);
18
19         int len = strlen(str+1);
20         memset(ispalindrome, false, sizeof(ispalindrome));
21         memset(dp, 0x3f, sizeof(dp));
22
23         for (int i = 1; i <= len; i++)
24         {
25             for (int l = i, r = i; str[l] == str[r] && l >= 1 && r <= len; l--, r++)
26                 ispalindrome[l][r] = true;
27             for (int l = i, r = i+1; str[l] == str[r] && l >= 1 && r <= len; l--, r++)
28                 ispalindrome[l][r] = true;
29         }
30
31         dp[0] = 0;
32         for (int i = 1; i <= len; i++)
33             for (int j = 1; j <= i; j++)
34                 if (ispalindrome[j][i])//[j,i]是不是回文
35                     dp[i] = min(dp[i], dp[j-1] + 1);
36
37         printf("%d\n", dp[len]);
38     }
39 }

原文地址:https://www.cnblogs.com/AlphaWA/p/9574643.html

时间: 2024-08-30 11:30:48

UVA-11584:Partitioning by Palindromes(基础DP)的相关文章

uva 11584 Partitioning by Palindromes 线性dp

// uva 11584 Partitioning by Palindromes 线性dp // // 题目意思是将一个字符串划分成尽量少的回文串 // // f[i]表示前i个字符能化成最少的回文串的数目 // // f[i] = min(f[i],f[j-1] + 1(j到i是回文串)) // // 这道题还是挺简单的,继续练 #include <algorithm> #include <bitset> #include <cassert> #include <

UVA - 11584 Partitioning by Palindromes[序列DP]

UVA - 11584 Partitioning by Palindromes We say a sequence of char- acters 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 lis

uva 11584 Partitioning by Palindromes(dp)

题目链接 题意:给定一个字符串,分解成多个子串,每个子串都是回文串,问最少能分成多少个子串. 题解: dp[i]表示前i个字符串分割成最少回文子串的数量: 0<=j<=i;如果字符串从j到i是回文串,那么dp[i]=min(dp[i],dp[j-1]+1); #include <iostream> using namespace std; int dp[1005]; string s; bool ok(int j,int i) { while(j<=i) { if(s[j]!

UVa 11584 Partitioning by Palindromes【DP】

题意:给出一个字符串,问最少能够划分成多少个回文串 dp[i]表示以第i个字母结束最少能够划分成的回文串的个数 dp[i]=min(dp[i],dp[j]+1)(如果从第j个字母到第i个字母是回文串) 想不明白的还是初始化 初始化为:dp[i]=i+1, 后来= =,发现应该是这样的 从第1个字母到第i个字母最多能够划分成i+1个回文串, 所以为了求最小值,每一个初始值初始化为一个极大地值, 所以dp[i]初始化为INF也可以 1 #include<iostream> 2 #include&l

UVa 11584 Partitioning by Palindromes (简单DP)

题意:给定一个字符串,求出它最少可分成几个回文串. 析:dp[i] 表示前 i 个字符最少可分成几个回文串,dp[i] = min{ 1 + dp[j-1] | j-i是回文}. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath&g

UVa 11584 Partitioning by Palindromes

/*---UVa 11584 Partitioning by Palindromes --用dp[i]表示前i个字母划分成最小回文串的个数,则有dp[i]=min{dp[j]+1}s[j+1...i]是一个回文串,状态O(n)个 每次有O(n)个决策,而判断是否是回文串复杂度O(n),这样总的复杂度O(n^3).如果事先预处理标记一下s[i...j]是否构成 回文串,这样总的复杂度O(n^2).标记s[i...j]是否构成回文串,用vis[i][j](i<=j)来标记,if s[i]!=s[j]

区间DP UVA 11584 Partitioning by Palindromes

题目传送门 1 /* 2 题意:给一个字符串,划分成尽量少的回文串 3 区间DP:状态转移方程:dp[i] = min (dp[i], dp[j-1] + 1); dp[i] 表示前i个字符划分的最少回文串, 4 如果s[j] 到 s[i]是回文串,那么可以从dp[j-1] + 1递推过来 5 */ 6 #include <cstdio> 7 #include <cstring> 8 #include <algorithm> 9 #include <cmath&g

Uva 11584 - Partitioning by Palindromes dp

Problem H: Partitioning by Palindromes 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 o

UVa 11584 Partitioning by Palindromes(DP 最少对称串)

题意  判断一个串最少可以分解为多少个对称串   一个串从左往后和从右往左是一样的  这个串就称为对沉串 令d[i]表示给定串的前i个字母至少可以分解为多少个对称串  那么对于j=1~i   若(i,j)是一个对称串  那么有  d[i]=min(d[i],d[j-1]+1)   然后就得到答案了 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N

UVa 11584 - Partitioning by Palindromes(线性DP + 预处理)

链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2631 题意: 输入一个由小写字母组成的字符串(长度不超过1000),你的任务是把它划分成尽量少的回文串.例如,racecar本身就是回文串:fastcar只能分成7个单字母的回文串,aaadbccb最少分成3个回文串:aaa, d, bccb. 分析: 设d[i]为字符0-i划分成