UVa Live 4394 String painter - 动态规划

题目传送门

  传送门

题目大意

  给定两个字符串$s$,$t$,每次可以选择一个$s$的一个区间将它变成一个字符,问最后将$s$变成$t$的最少操作数。

  当$s$某一段中每个字符都不同的时候,等价于对一个空串操作变成$t$的这一段。

  考虑用$g_{l, r}$表示将空串,变成$t_{l}t_{l + 1}\cdots t_{r}$的最少操作数。

  不难发现,如果我对一个区间$[l, r]$进行操作,满足下面两个条件不会更劣:

  • $t_{l} = t_{r}$
  • 在这之后的操作要么被$[l + 1, r - 1]$包含,要么与$[l, r]$无交。

  第一点比较显然,第二点是因为如果之后的操作覆盖了$r$或者覆盖了$l$,那么这一次操作对$r$或者$l$的修改是无效的,我可以把它替换成更小的区间。

  每次考虑对当前区间的第一次操作,转移可以分为下面几个:

  • 如果是对整个区间进行操作,那么它必然满足$t_{l} = t_{r}$,它的操作次数等于$g_{l + 1, r}$。
  • 如果没有对整个区间进行操作,那么考虑对包含左端点或者右端点的一个操作。
    等价于在中间枚举一个中间点$i$,使得$t_{i} = t_{r}$或者$t_{i} = t_{s}$用$g_{l, i - 1} + g_{i, r}$或者$g_{l, i} + g_{i + 1, r}$。

  考虑上原来的串$s$与空串有什么不同,如果一个位置上$s_{i} = t_{i}$,那么这个位置可以不用操作。如果我硬点它不操作,那么所有操作区间都不能跨过它。(即使操作的字符和它相等,但那样和它被看成空没有什么不同)。

  所以再设$f_{i}$表示使$s$的前$i$个字符与$t$相同的最小代价。这个转移比较显然。

  • 如果$s_{i} = t_{i}$,那么用$f_{i - 1}$更新$f_{i}$
  • 否则枚举最后一个被当成空串的区间。

  时间复杂度$O(n^{3})$

Code

 1 /**
 2  * UVa Live
 3  * Problem#4394
 4  * Accepted
 5  * Time: 43ms
 6  */
 7 #include <iostream>
 8 #include <cstdlib>
 9 #include <cstring>
10 #include <cstdio>
11 using namespace std;
12 typedef bool boolean;
13
14 template <typename T>
15 void pfill(T* pst, const T* ped, T val) {
16     for (; pst != ped; *(pst++) = val);
17 }
18
19 const int N = 105;
20 const signed inf = (signed) (~0u >> 1);
21
22 int n;
23 char A[N], B[N];
24 int f[N], g[N][N];
25 boolean vis[N][N];
26
27 inline boolean init() {
28     if (scanf("%s", A + 1) == -1)
29         return false;
30     scanf("%s", B + 1);
31     n = strlen(A + 1);
32     return true;
33 }
34
35 int dp(int l, int r) {
36     if (l == r)
37         return 1;
38     if (vis[l][r])
39         return g[l][r];
40     int& rt = g[l][r];
41     rt = inf, vis[l][r] = true;
42     if (B[l] == B[r])
43         rt = min(dp(l + 1, r), dp(l, r - 1));
44
45     for (int i = l; i < r; i++)
46         if (B[l] == B[i])
47             rt = min(rt, dp(l, i) + dp(i + 1, r));
48     for (int i = l + 1; i <= r; i++)
49         if (B[i] == B[r])
50             rt = min(rt, dp(l, i - 1) + dp(i, r));
51     return rt;
52 }
53
54 inline void solve() {
55     pfill(vis[1], vis[n + 1], false);
56     f[0] = 0;
57     for (int i = 1; i <= n; i++) {
58         f[i] = inf;
59         if (A[i] == B[i])
60             f[i] = f[i - 1];
61         for (int j = i; j; j--)
62             f[i] = min(f[i], f[j - 1] + dp(j, i));
63     }
64     printf("%d\n", f[n]);
65 }
66
67 int main() {
68     while (init())
69         solve();
70     return 0;
71 }

原文地址:https://www.cnblogs.com/yyf0309/p/9912275.html

时间: 2024-10-02 14:44:03

UVa Live 4394 String painter - 动态规划的相关文章

uva live 4394 String painter 区间dp

// uva live 4394 String painter // // 这一题是训练指南上dp专题的习题,初看之下认为仅仅是稍微复杂了一点 // 就敲阿敲阿敲,两个半小时后,发现例子过了.然而自己给出的数据跪了 // 交了也wa了,才发现,自己的方法是有问题的,假设是将两个串同一时候考虑 // 的话,比方: dp[i][j] 表示从i到j,s串刷成目标b串所须要的最小的花费 // 然后依据区间的端点的字符特点,进行状态转移,然而可能是我太搓了, // 发现这种状态转移是不正确的.比方edc和

uva live 4394 String painter 间隔dp

// uva live 4394 String painter // // 问题是,在培训指导dp运动主题,乍一看,我以为只是一点点复杂 // A A磕磕磕,两个半小时后,.发现超过例子.然而,鉴于他们跪在数据 // 还要wa.才发现,自己的方法是有问题的,假设是将两个串同一时候考虑 // 的话.比方: dp[i][j] 表示从i到j,s串刷成目标b串所须要的最小的花费 // 然后依据区间的端点的字符特点,进行状态转移.然而可能是我太搓了. // 发现这种状态转移是不正确的,比方edc和cde.

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

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 2476 (string painter) 字符串刷子

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

HDU 2476 String painter(字符串转变)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2476 题意:给定两个长度相同的串A和B.每次操作可以将A的连续一段改变为另一个字母.求将A转换成B最少需要多少次操作? 思路:首先,我们假设没有A串,那么这就跟 BZOJ1260是一样的了,即答案为DFS(0,n-1)...但是这里有了A串就有可能使得操作次数更少.因为可能有些对应位置字母是相同的.我们设 ans[i]表示前i个字母变成一样的,那么若A[i]=B[i]则ans[i]=ans[i-1]

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

hdu2476——String painter

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