划分成回文串(Partitioning by Palindromes)UVA11584题解
题目大意
输入一个由小写字母组成的字符串,将它划分成尽量少的回文串。eg. racecar本身就是回文串,fastcar只能分成7个单字母的回文串,aaabdccb最少分成3个回文串:aaa, d, bccb,输出划分后的回文串的数量
思路梳理
可以用贪心吗?
“划分成尽量少的回文串”,很容易让人想到“尽量让每个回文串最长”。使划分后的字符串尽量长,思路非常简单:从第一个开始一个个比较是否回文即可。时间复杂度\(O\)\((\)\(n^2\)\()\)
正确吗?
若输入aaaacbcccccbca,贪心会选择aaaa cbc ccc cbc a但显然答案是aaa acbcccccbca所以不是贪心
那就dp咯
令dp[i]表示从1到i子串的结果,则当j+1至i是回文串时,dp[i] = min(dp[i], dp[j] + 1)
代码
预处理
先将所有的回文串预处理出来
int sz = s.size() ;
for(int i = 0 ; i < sz ; i ++ )
{
check[i][i] = 1 ;
check[i][i + 1] = (s[i] == s[i + 1]) ;
}
for(int i = 1 ; i < sz ; i ++) for(int j = 0 ; j < i - 1 ; j ++ ) if(s[i] == s[j]) check[j][i] = check[j+1][i-1]; else check[j][i] = 0 ;
状态转移
for(int i = 0 ; i < s.size() ; i ++ )
{
if( i == 0 ) dp[i] = 1 ;
else dp[i] = dp[i - 1] + 1 ;
for(int j = 0 ; j < i ; j ++ ) if(check[j][i] == 1) dp[i] = min(dp[i], dp[j - 1] + 1) ;
}
完整代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2005 ;
int t ;
string s ;
int dp[MAXN] ;
int check[MAXN][MAXN] ;
void pre_work()
{
int sz = s.size() ;
for(int i = 0 ; i < sz ; i ++ )
{
check[i][i] = 1 ;
check[i][i + 1] = (s[i] == s[i + 1]) ;
}
for(int i = 1 ; i < sz ; i ++) for(int j = 0 ; j < i - 1 ; j ++ ) if(s[i] == s[j]) check[j][i] = check[j+1][i-1]; else check[j][i] = 0 ;
}
int main()
{
cin >> t ;
while( t -- )
{
cin >> s ;
pre_work() ;
// dp[0] = 1 ;
for(int i = 0 ; i < s.size() ; i ++ )
{
if( i == 0 ) dp[i] = 1 ;
else dp[i] = dp[i - 1] + 1 ;
for(int j = 0 ; j < i ; j ++ ) if(check[j][i] == 1) dp[i] = min(dp[i], dp[j - 1] + 1) ;
}
cout << dp[s.size() - 1] << endl ;
}
return 0 ;
}

浙公网安备 33010602011771号