hdu 2476 String painter 区间dp

本文介绍了一种使用区间动态规划方法解决特定字符串涂改问题的算法实现。该问题要求将一个字符串通过最少次数的涂改变为另一个字符串。文章详细解析了状态转移方程,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

#define inf 0x3f3f3f3f
#define LL long long
using namespace std;

/************************************************

designer:hl
time:2016/11/23
Exe.Time:31 ms
Exe.Memory:1604 KB

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2476

题意:有一把神奇的刷子可以把一段字符串刷成同一个字符。最小刷几次能把上面字符串刷成下面的字符串

题解:第一次搞区间dp 还是有难度的 看了http://blog.youkuaiyun.com/a601025382s/article/details/12379565 的代码
 然后自己独立写了一遍 还要多复习这道题和多做区间dp的题目 具体的状态方程是会了。
 dp[l][r]代表从l到r满足条件需要的最小的涂改数量 
 一开始我们可以不看第一个字符串。直接看修改过的字符串 当i j中有一个z让changed[l]==changed[r]的时候 说明这段可以
 优化相当于消除这个l是免费的 比如aba 那么消除第一个a是免费的。只需要消除ba就可以了。于是出现状态转移方程
  dp[l][r] = min(dp[l][r], dp[l + 1][k] + dp[k + 1][r]);
  最后在看原有字符串 如果原有字符串中有i 满足origin[i]==changed[i]那么这个字符串就可以不涂 从0到i的最小解就等于dp[0][i-1]
  再做一遍计算最小值判断就可以得到答案了

************************************************/


using namespace std;
int dp[111][111];


int main() {
    int i, j, k, l, m, n, len, r;
    char origin[111], changed[111];
    while (~scanf("%s", origin)) {
        scanf("%*c");
        scanf("%s", changed);
        scanf("%*c");
        n = strlen(changed);
        //cout<<origin<<"  "<<changed<<endl;
        for (i = 0; i < n; i++) {
            dp[i][i] = 1; //表示把i涂掉需要一步
        }
        for (len = 2; len <= n; len++) { //枚举长度
            for (l = 0; l < n - len + 1; l++) { //枚举left
                r = l + len - 1;//于是right就得到了
                dp[l][r] = min(dp[l + 1][r] + 1, dp[l][r - 1] + 1);//这串的初始值相当于l+1到r的长度消去l和l到r-1的长度再消去r
                for (k = l + 1; k <= r; k++) {//枚举分割点
                    if (changed[l] == changed[k]) {//如果这两个相等说明这段区间存在优化的空间
                        dp[l][r] = min(dp[l][r], dp[l + 1][k] + dp[k + 1][r]);
                    }
                }
            }
        }
        for (i = 0; i < n; i++) {
            if (origin[i] == changed[i]) { //如果这两个字符相同。则直接可以使用不要这字符的情况dp[0][i-1]
                if (i == 0) {
                    dp[0][0] = 0;
                }
                else {
                    dp[0][i] = dp[0][i - 1];
                }
            } else { //如果不相同 由于上面重新计算了 那么就可以用递推式
                for (j = 0; j < i; j++) {
                    dp[0][i] = min(dp[0][j] + dp[j + 1][i], dp[0][i]);
                }
            }
        }
        printf("%d\n", dp[0][n - 1]);
    }


    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值