UVA1437 题解

UVA1437 String painter

题目大意

给定两个字符串 $A$、$B$,其中 $A$ 可以通过若干次变换得到 $B$,试求出变换次数。

思路

显然是一道区间 DP。

首先不考虑相同的字符,可以令 $f_{i,j}$ 表示将空白串的区间 $[i,j]$ 变换为 $B_{i \sim j}$ 需要的最小步数。

考虑两种情况:

  1. 当 $B_i \ne B_j$ 时,这意味着需要对字符串进行变换,通过枚举断点 $k$ 进行转移,思路跟一般的区间 DP 差不多,这里不做过多解释。
  2. 当 $B_i = B_j$ 时,这意味着无需对字符串进行变换,可以直接由 $f_{i+1,j}$ 或者 $f_{i,j - 1}$ 转移得到。

综上所述,易得状态转移方程如下:$$ f(i, j) = \begin{cases} \min \left\{f(i, k) + f(k + 1, j) \mid i \le k < j \right\} & B_i \ne B_j \\ \max \left\{f(i + 1, j), f(i, j - 1) \right\} & B_i = B_j \\ \end{cases} $$ 有了上面的 DP 数组,现在我们就可以考虑处理相同字符。令 $g_i$ 表示将 $A_{1 \sim i}$ 变换成 $B_{1 \sim i}$ 需要的最小步数。考虑两种情况:

  1. 当 $A_i = B_i$ 时,则不需要再做其他修改,此时 $g_i = g_{i - 1}$。
  2. 当 $A_i \ne B_i$ 时,则需要进行修改,通过枚举断点 $j$ 进行转移,此时 $g_i = \min \left\{f_{j + 1, i} + g_j \mid 1 \le j < i \ \right\}$。

综上所述,易得状态转移方程如下:$$ g_i = \begin{cases} g_{i - 1} & A_i \ne B_j \\ \min \left\{f_{j + 1, i} + g_j \mid 1 \le j < i \ \right\} & A_i = B_j \\\end{cases} $$ 此外还有一种特殊情况:在转移之后可能会出现 $g_i > f_{1, i}$ 的情况,这个时候的 $g_i$ 就不是最优解了,因此还需要令 $g_i = \min \left\{g_i, f_{1, i})\right\}$。最终答案显然是 $g_n$,具体细节请看代码……

代码

#include <iostream>
#include <cstring>
#define MAXN 105
using namespace std;
char a[MAXN], b[MAXN];
int n, f[MAXN][MAXN], g[MAXN];
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0); // 加速
    while(cin >> (a + 1) >> (b + 1)){
        n = strlen(a + 1);
        memset(f, 998244353, sizeof(f));
        memset(g, 998244353, sizeof(g)); // 记得初始化
        for(int i = 0 ; i <= n ; i ++)f[i][i] = 1;
        for(int len = 1 ; len <= n ; len ++) // 枚举长度
            for(int i = 1, j = i + len ; j <= n ; i ++ , j ++){
                if(b[i] == b[j])f[i][j] = max(f[i + 1][j], f[i][j - 1]);
                else for(int k = i ; k < j ; k ++)f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j]); // 枚举断点
            }g[1] = a[1] != b[1];
        for(int i = 2 ; i <= n ; i ++){
            if(a[i] == b[i])g[i] = min(g[i], g[i - 1]);
            else for(int j = 1 ;j < i ; j ++)g[i] = min(g[i], g[j] + f[j + 1][i]); // 枚举断点
            g[i] = min(g[i], f[1][i]); // 特判
        }cout << g[n] << endl; // 输出答案
    }return 0;
}
posted @ 2023-08-24 10:24  tsqtsqtsq  阅读(12)  评论(0)    收藏  举报  来源