划分成回文串(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 ;
}
posted @ 2022-11-29 02:12  Lwen1243  阅读(146)  评论(0)    收藏  举报