例题9-7 划分成回文串 UVa11584

1.题目描述:点击打开链接

2.解题思路:本题要求划分回文串,且个数尽可能的少。可以用动态规划解决。先提前判断i~j是否构成回文串,时间复杂度是O(N^2),然后定义d(i)表示0~i-1划分成的回文串的最小个数。则状态转移方程为:

d(i)=min(d(i),d(j)+1)(s[j...i]是回文串)

上式中,d(i)的初始值是i,这样每次判断只需要O(1)的时间,总时间复杂度是O(N^2)。当然,判断回文串的过程可以和状态转移相结合,细节请参考第二份代码。

3.代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

#define maxn 1030000
int vis[maxn];
int d[maxn];
int n;
int main()
{
	//freopen("test.txt", "r", stdin);
	cin >> n;
	while (n--)
	{
		string str;
		cin >> str;
		memset(vis, 0, sizeof(vis));
		memset(d, 0, sizeof(d));
		int len = str.length();
		for (int i = 0; i <= len; i++)d[i] = i;
		for (int i = 0; i < 2 * len - 1; i++)//枚举中心,判断i到j是否为回文串
		{
			int p;
			int m = i / 2;
			for (int j = m; j >=0; j--)
			{
				if (i - j<len&&str[j] == str[i - j])
				{
					p = (j << 10) | (i - j);
					vis[p] = 1;
				}
				else break;
			}
		}
		int q = 0;
		for (int i = 0; i <= len; i++)//枚举起点,终点
		{
			for (int j = 0; j <= i - 1; j++)
			{
				q = (j << 10) | (i - 1);
				if (vis[q])
					d[i] = min(d[i], d[j] + 1);
			}
		}
		printf("%d\n", d[len]);
	}
	return 0;
}

参考代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

#define N 1002

int f[N];
bool d[N][N];

int main()
{
	freopen("test.txt","r", stdin);
	int n, t, i, j, result;
	cin >> t;
	while (t--)
	{
		string s;
		cin >> s;
		n = s.length();
		memset(f, 1000000, sizeof(f));
		memset(d, false, sizeof(d));
		for (int i = 0; i <= n; i++)//f[i]表示i到n划分成的最小回文串的个数
			f[i] = n - i;
		for (int i = n - 1; i >= 0; i--)//i是起点,逆序枚举
		for (int j = i; j < n; j++)//j是终点,顺序枚举
		if (s[i] == s[j] && (j - i < 2 || d[i + 1][j - 1])) //如果j-i<2那么只需要直接用s[i]==s[j]判断即可,否则,用d[i+1][j-1]来判断是否为回文串
		{
			d[i][j] = true;
			f[i] = min(f[i], f[j + 1] + 1);
		}
		cout << f[0] << endl;
	}
	return 0;
}



时间: 2024-08-01 19:40:03

例题9-7 划分成回文串 UVa11584的相关文章

UVa 11584 划分成回文串

https://vjudge.net/problem/UVA-11584 题意: 给出一串字符,把它划分成尽量少的回文串. 思路: 用d[i]表示划分到i时所能划分的最小个数,转移方程为d[i]=min{d[i],d[j]+1},当然前提是j+1~i是回文串,我们可以预处理计算出所有的回文串,这样转移时就比较方便. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<s

Uva 11584,划分成回文串

题目链接:https://uva.onlinejudge.org/external/115/11584.pdf 题意: 一个字符串,将它划分一下,使得每个串都是回文串,求最少的回文串个数. 分析: d(i)到第 i 个字符时的最优解(即最少划分为几个回文串),就有方程  d(i) = min(d(j)) + 1;(其中s[j+1,i]要是回文串). 这样一来,枚举就是O(n^2)的复杂度,如果按照普通的判断s[j+1,i]是否是回文串,时间复杂度为O(n^3);先用O(n^2)的复杂度预处理is

POJ 3280 Cheapest Palindrome(区间DP求改成回文串的最小花费)

题目链接:http://poj.org/problem?id=3280 题目大意:给你一个字符串,你可以删除或者增加任意字符,对应有相应的花费,让你通过这些操作使得字符串变为回文串,求最小花费.解题思路:比较简单的区间DP,令dp[i][j]表示使[i,j]回文的最小花费.则得到状态转移方程: dp[i][j]=min(dp[i][j],min(add[str[i]-'a'],del[str[i]-'a'])+dp[i+1][j]); dp[i][j]=min(dp[i][j],min(add[

uva--10716Evil Straw Warts Live +回文串+贪心

题意: 输入一个字符串,我们可以交换这个字符串中的相邻字符:问至少经过多少步交换可以得到一个回文串:如果无论怎么交换都得不到回文串,输出"Impossible": 思路: 首先由回文串的定义和性质,可以得到两种不可能情况:1.当这个串长度为奇数时,如果出现次数为奇数次字母的数目不为1,则显然不可能.2.当这个串长度为偶数时,如果出现次数为奇数次字母的个数大于0,则不可能. 除去这两种不可能的情况后,这个串就一定可以转成回文串.我们只需要考虑0--len/2(len为串长)的部分,对于第

[LeetCode] Palindrome Partitioning II 拆分回文串之二

Given a string s, partition s such that every substring of the partition is a palindrome. Return the minimum cuts needed for a palindrome partitioning of s. For example, given s = "aab", Return 1 since the palindrome partitioning ["aa"

回文串划分

题目: 有一个字符串S,求S最少可以被划分为多少个回文串. 例如:abbaabaa,有多种划分方式. a|bb|aabaa - 3 个回文串 a|bb|a|aba|a - 5 个回文串 a|b|b|a|a|b|a|a - 8 个回文串 其中第1种划分方式的划分数量最少. Input 输入字符串S(S的长度<= 5000). Output 输出最少的划分数量. Sample Input abbaabaa Sample Output 3 分析:题目意思还是很好懂的,不像比赛的几个题目我连题意都没看懂

UVA - 11584 划分字符串的回文串子串; 简单dp

/** 链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34398 UVA - 11584 划分字符串的回文串子串: 简单dp 题目大意: 给一个字符串, 要求把它分割成若干个子串,使得每个子串都是回文串.问最少可以分割成多少个. 定义:dp[i]表示前0~i内的字符串划分成的最小回文串个数: dp[i] = min(dp[j]+1 | j+1~i是回文串); 先预处理flag[i][j]表示以i~j内的字符串为回文串

UVA 11584 Partitioning by Palindromes 划分回文串 (Manacher)

d[i]表示前面i个字符划分成的最小回文串个数,那么转移i字符和之前的某个字符j构成回文串形成的新划分,所以要判断前面的字符j+1到i是不是回文串,可以用Manacher算法预处理出来. #include <iostream> #include <algorithm> #include <cstring> #include<cstdio> using namespace std; const int MAX = 1042; int len, p[2*MAX]

51Nod-1154 回文串划分

有一个字符串S,求S最少可以被划分为多少个回文串. 例如:abbaabaa,有多种划分方式. a|bb|aabaa - 3 个回文串 a|bb|a|aba|a - 5 个回文串 a|b|b|a|a|b|a|a - 8 个回文串 其中第1种划分方式的划分数量最少. Input 输入字符串S(S的长度<= 5000). Output 输出最少的划分数量. Input示例 abbaabaa Output示例 3 题解:这个题目,数据比较水,n^3可以过,首先,设dp[i]表示前i位的最少字符串数,所以