String painter (hdu 2476 DP好题)

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

题目大意:

给出两个等长的串S, T, 要将S变成T, 每次可以把S的连续的一段变成相同的字母,求最少操作数。

这题网上看了好多题解,理解了好久, 记录一下我的理解吧。

首先求出把空串变成T的最少次数。

dp[i][j] 表示把空串变成T[i ... j]的最少次数。

首先dp[i][j] = dp[i + 1][j].

然后有一个性质。如果两次染色的区间有交, 那么小的区间一定完全包含于大的区间(左右端点也不会重合), 且一定是大区间 在小区间之前染色(否则 小区间完全被覆盖 就没用了)。

如果不是这样, 可以改造一下区间 变成这样。

所以第一次染色 一定是[i, k],   然后T[k + 1, j]可以单独考虑(因为染色不能再和[i, k]有交了)。

那么如何选这个k呢?

只要考虑T[i] = T[k]的位置, 如果不是,可以调整染色区域长度 变成右端点的颜色和 T[i]一样。

然后有另外一个性质:

如果T[i] = T[j], dp[i][j] = dp[i + 1][j].    只要第一次染色区域选择[i, j],  就可以和dp[i + 1][j] 对应起来。

综上 dp[i][j] = min{dp[i + 1][j] + 1,    dp[i + 1][k]  + dp[k][j] (T[i] == T[k]) }

最后根据dp数组再做一次DP。

ans[i] 表示考虑S[1 ... i]  T[1 ... i]

如果S[i] == T[i]  显然ans[i] = ans[i - 1]

否则肯定有一段S的区间[k ... i]  都被刷子刷过。  那么这一段的情况就是dp[k][i].

所以ans[i] = min(ans[k] + dp[k + 1][i]).

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <map>
 8 #include <queue>
 9 #include <set>
10 using namespace std;
11
12 #define X first
13 #define Y second
14 #define N 110
15 #define M 500010
16
17 typedef long long ll;
18 const int INF = 1 << 30;
19 const int Mod = 1000000007;
20
21 char s[N], t[N];
22 int dp[N][N], ans[N];
23
24 int main()
25 {
26     //freopen("in.in", "r", stdin);
27     //freopen("out.out", "w", stdout);
28
29     while (scanf("%s %s", s + 1, t + 1) != EOF)
30     {
31         int n = strlen(s + 1);
32         for (int i = 1; i <= n; ++i) dp[i][i] = 1;
33         for (int len = 2; len <= n; ++len)
34         {
35             for (int i = 1; i + len - 1 <= n; ++i)
36             {
37                 int j = i + len - 1;
38                 dp[i][j] = dp[i + 1][j] + 1;
39                 for (int k = i + 1; k <= j; ++k)
40                     if (t[i] == t[k]) dp[i][j] = min(dp[i][j], dp[i + 1][k] + dp[k + 1][j]);
41             }
42         }
43         ans[1] = (s[1] != t[1]);
44         for (int i = 2; i <= n; ++i)
45         {
46             if (s[i] == t[i]) ans[i] = ans[i - 1];
47             else
48             {
49                 ans[i] = dp[1][i];
50                 for (int k = 1; k < i; ++k)
51                     ans[i] = min(ans[i], ans[k] + dp[k + 1][i]);
52             }
53         }
54         printf("%d\n", ans[n]);
55     }
56
57
58     return 0;
59 }

时间: 2024-12-28 01:31:26

String painter (hdu 2476 DP好题)的相关文章

HDU 2476 String painter(区间DP啊)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2476 Problem Description There are two strings A and B with equal length. Both strings are made up of lower case letters. Now you have a powerful string painter. With the help of the painter, you can cha

HDU 2476 String painter(区间dp)

String painter Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2171    Accepted Submission(s): 956 Problem Description There are two strings A and B with equal length. Both strings are made up

HDOJ 题目2474 String painter(区间DP)

String painter Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2520    Accepted Submission(s): 1134 Problem Description There are two strings A and B with equal length. Both strings are made up

hdu2476 String painter(区间dp)

Problem Description There are two strings A and B with equal length. Both strings are made up of lower case letters. Now you have a powerful string painter. With the help of the painter, you can change a segment of characters of a string to any other

UVA 4394 - String painter(字符串区间DP)

String painter                           Time Limit:3000MS    Memory Limit:0KB    64bit IO Format:%lld & %llu Description There are two strings A and B with equal length. Both strings are made up of lower case letters. Now you have a powerful string

HDU 2476 String painter (区间DP)

题意:给出两个串a和b,一次只能将一个区间刷一次,问最少几次能让a=b 思路:首先考虑最坏的情况,就是先将一个空白字符串刷成b需要的次数,直接区间DP[i][j]表示i到j的最小次数. 再考虑把a变成b的次数 ans[i]:a从(0,i)变成b(0,i)所需的最小次数 初始化ans[i]=dp[0][i] 如果a[i]==b[i],则ans[i]=ans[i-1]; 由小区间更新到大区间 1 //#pragma comment(linker, "/STACK:167772160")//

uvalive 4394 string painter (序列dp)

两个字符串,s是原串,t是目标串,一次可以把s的任意段所有字母变成同一个字母,问用最少次数将s变成t. 状态转移方程为cnt[i] = min(cnt[i], dp(j+1,i-1,t[i])+1+(j>0 ? cnt[j-1]:0)) 代码如下: #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include&

hdu 2571 dp入门题

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2571 常规dp,刚好让我这菜鸟来找找 找状态转移方程的感觉.. 定义dp[i][j]  表示的是第i行j列所拥有的最大的幸运值. dp[i][j] 由三种情况转移而来:1.从上面一个坐标转移而来,即dp[i-1][j] .2.由左边转移过来,即dp[i][j-1].3.由他同一行中的 j 的因数列转移过来的(但是要除了j自己),即dp[i][ j 的因数列] 找出这三种情况中最大的就可以了,dp[i

hdu 2476 String painter(区间dp)

String painter                                                                                                Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)