划分成回文串 Partitioning by Palindromes

在这里插入图片描述
UVA11584
这道题需要两次dp

第一次

定义 S S 为字符串, I s P a l i n d r o m e [ i ] [ j ] IsPalindrome[i][j] 为第 i i 个字符到第 j j 个字符组成的子串是否为回文 i j i\leq j
初始化
I s P a l i n d r o m e [ i ] [ i ] = t r u e I s P a l i n d r o m e [ i 1 ] [ i ] = ( S [ i ] = = S [ i 1 ] ) IsPalindrome[i][i]=true\\ IsPalindrome[i-1][i]=(S[i]==S[i-1])
转移方程
I s P a l i n d r o m e [ i ] [ j ] = I s P a l i n d r o m e [ i + 1 ] [ j 1 ] & & ( s [ i ] = = s [ j ] ) IsPalindrome[i][j] = IsPalindrome[i + 1][j - 1] \&\& (s[i] == s[j])
如果子串的左边一个字符和其右边一个字符相等,那在这个字串往左右各拓展一格字符形成的新字串仍然时回文串。

第二次

定义 d p [ j ] dp[j] 为前j各字符组成的字串划分成的最小回文串数量。
初始化 d p [ j ] = 0 dp[j]=0
转移方程

for (int j = 1; j <= Len; ++j) {
		//将第j个字符看作单独的字串
		dp[j] = dp[j - 1] + 1;
		for (int i = 1; i < j; ++i) {
			//如果i到j是回文串
			if (IsPalindrome[i][j]) {
				//那i到j看作一个回文串
				//dp[j]=前i-1个字符组成的子串能划分的最小数量+1
				dp[j] = min(dp[j], dp[i - 1] + 1);
			}
		}
	}
AC代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int dp[1001];
bool IsPalindrome[1001][1001];
char s[1002];
int Len;
void InitIsPalindrome() {
	Len = strlen(s + 1);
	memset(IsPalindrome, false, sizeof(IsPalindrome));
	for (int i = 1; i <= Len; ++i) {
		IsPalindrome[i][i] = true;
		IsPalindrome[i - 1][i] = (s[i] == s[i - 1]);
	}
	for (int j = 2; j <= Len; ++j) {
		for (int i = 1; i < j - 1; ++i) {
			IsPalindrome[i][j] = IsPalindrome[i + 1][j - 1] && (s[i] == s[j]);
		}
	}
}
int getAns() {
	memset(dp, 0x0, sizeof(dp));
	for (int j = 1; j <= Len; ++j) {
		dp[j] = dp[j - 1] + 1;
		for (int i = 1; i < j; ++i) {
			if (IsPalindrome[i][j]) {
				dp[j] = min(dp[j], dp[i - 1] + 1);
			}
		}
	}
	return dp[Len];
}
int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		scanf("%s", s + 1,1000);
		InitIsPalindrome();
		printf("%d\n", getAns());
	}
	return 0;
}
发布了22 篇原创文章 · 获赞 26 · 访问量 4597

猜你喜欢

转载自blog.csdn.net/qq_42971794/article/details/104031810