回文串(DP)

天下人类一家亲,望人类停止斗争!
题目描述
Friday is Polycarpus’ favourite day of the week. Not because it is followed by the weekend, but because the lessons on Friday are 2 IT lessons, 2 math lessons and 2 literature lessons. Of course, Polycarpus has prepared to all of them, unlike his buddy Innocentius. Innocentius spent all evening playing his favourite game Fur2 and didn’t have enough time to do the literature task. As Innocentius didn’t want to get an F, he decided to do the task and read the book called “Storm and Calm” during the IT and Math lessons (he never used to have problems with these subjects). When the IT teacher Mr. Watkins saw this, he decided to give Innocentius another task so that the boy concentrated more on the lesson and less — on the staff that has nothing to do with IT.

Mr. Watkins said that a palindrome is a string that can be read the same way in either direction, from the left to the right and from the right to the left. A concatenation of strings a, b is a string ab that results from consecutive adding of string b to string a. Of course, Innocentius knew it all but the task was much harder than he could have imagined. Mr. Watkins asked change in the “Storm and Calm” the minimum number of characters so that the text of the book would also be a concatenation of no more than k palindromes. Innocentius can’t complete the task and therefore asks you to help him.

Input
The first input line contains a non-empty string s which is the text of “Storm and Calm” (without spaces). The length of the string s does not exceed 500 characters. String s consists of uppercase and lowercase Latin letters. The second line contains a single number k (1 ≤ k ≤ |s|, where |s| represents the length of the string s).

Output
Print on the first line the minimum number of changes that Innocentius will have to make. Print on the second line the string consisting of no more than k palindromes. Each palindrome should be non-empty and consist of uppercase and lowercase Latin letters. Use the character “+” (ASCII-code 43) to separate consecutive palindromes. If there exist several solutions, print any of them.

The letters’ case does matter, that is an uppercase letter is not considered equivalent to the corresponding lowercase letter.

  • 题目大意:给你一个字符串, 将这个字符串在n次的改动下变成几个(不超过k个)回文串。

  • 历程: 首先题目的理解我就已经输了,真的是太难理解了, 搞了很长时间才明白(大概半小时),然后一开始我直接就想到了二分加
    dfs, 但是题目的范围有点大,感觉这样是过不了的,想了一会,还是没有思路,最后在网上搜了一下,好像是个dp, 其实一开始我也想
    到是不是dp,但是奈何自己有点菜,在摸索方向的时候没有深入的考虑,只是感觉和dp 不沾边,但是看着这个数据的范围又感觉是dp。
    但是明确了方向后感觉后续的进展就很快了,还是需要联系这样的能力的。

  • 如何想到dp?首先我们看到题目想到的是怎样将串分割才能得到最优解,分割成的每个独立的串变成回文串的步数是一定的,那么我们的
    任务就变成了在空隙中选出一些位置使得达到题目的要求时改变的步数最少,就像01背包一样,我们也是考虑每个背包选或者不选,这就
    能引导我们向着dp 的方向走。

  • 状态的表示: f [ i ] [ j ] f[i][j] f[i][j]表示将前 i i i个字母分成 j j j组的最小步数,我们只需要枚举最后一组的左边界,即可得到状态转移方程
    f [ i ] [ j ] = m i n ( f [ 1 ] [ j − 1 ] + c o s t [ 1 + 1 ] [ i ] , f [ 2 ] [ j − 1 ] + c o s t [ 2 + 1 ] i ] … f [ i − 1 ] [ j − 1 ] + c o s t [ i ] [ i ] ) f[i][j] = min(f[1][j - 1] + cost[1 + 1][i], f[2][j - 1] + cost[2 + 1]i]…f[i - 1][j - 1] + cost[i][i]) f[i][j]=min(f[1][j1]+cost[1+1][i],f[2][j1]+cost[2+1]i]f[i1][j1]+cost[i][i])

代码不够精简。

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 510;

int n;

string a;

int f[N][N], dp[N][N];

int main()
{
    cin >> a >> n;
    
    for (int i = 0; i < a.size(); i ++)
        for (int j = i; j <= a.size(); j ++)
        {
            int cnt = 0;
            for (int l = i, r = j; l < r; l ++, r --) 
                if (a[l] != a[r]) cnt ++; 
            f[i][j] = cnt;
        }
        
    
    
    memset (dp, 0x3f, sizeof dp);
    
    for (int i = 0; i < a.size(); i ++) dp[i][1] = f[0][i];
    
    
    dp[0][1] = f[0][0];
    
    for (int i = 0; i < a.size(); i ++) 
        for (int j = 2; j <= n; j ++) 
            for (int k = 0; k < i; k ++) 
            {
                dp[i][j] = min (dp[k][j - 1] + f[k + 1][i], dp[i][j]);
            }
    
    string str;
    int res = 1e9, ans;
    for (int i = 1; i <= n; i ++) 
    {
        if  (res > dp[a.size () - 1][i]) res = dp[a.size() -1][i], ans = i;
    }
    
    int temp = a.size () - 1;
    while (ans)
    {
        if  (ans == 1)
        {
            string t =  a.substr (0, temp + 1);
            for (int l = 0, r = t.size() - 1; l < r; l ++, r -- ) t[l] = t[r]; 
            str += t;
            break;
        }
        
        for (int i = temp - 1; i >= 0; i --)
        {
            if (dp[i][ans - 1] + f[i + 1][temp] == dp[temp][ans]) 
            {
                string t = a.substr (i + 1, temp -i);
                
                for (int l = 0, r = t.size() - 1; l < r; l ++, r -- ) t[l] = t[r]; 
                
                str += t + '+';
                temp = i;
                break;
            }
        }
            ans --;
    }
    reverse (str.begin(), str.end());
    printf ("%d\n", res);
    cout << str << endl;
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值