#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;
}
hdu 2476 String painter 区间dp
最新推荐文章于 2021-07-31 18:20:15 发布