P2758 编辑距离
题目描述
设 \(A\) 和 \(B\) 是两个字符串。我们要用最少的字符操作次数,将字符串 \(A\) 转换为字符串 \(B\)。这里所说的字符操作共有三种:
- 删除一个字符;
- 插入一个字符;
- 将一个字符改为另一个字符。
\(A, B\) 均只包含小写字母。
输入格式
第一行为字符串 \(A\);第二行为字符串 \(B\);字符串 \(A, B\) 的长度均小于 \(2000\)。
输出格式
只有一个正整数,为最少字符操作次数。
输入输出样例 #1
输入 #1
sfdqxbw
gfdgw
输出 #1
4
说明/提示
对于 \(100 \%\) 的数据,\(1 \le |A|, |B| \le 2000\)。
题解
考虑动态规划。
设字符串为\(a, b\),长度分别为\(n, m\)。
定义\(dp_{i, j}\)是字符串\(a\)前\(i\)个字符转换到字符串\(b\)前\(j\)个字符所需要的最小操作次数。
那么就有
\[dp_{i, j} =
\begin{cases}
0, & i = 0, j = 0 \\
dp_{i, j - 1} + 1, &i = 0, 1 \le j \le m \\
dp_{i - 1, j} + 1, & 1 \le i \le n, j = 0 \\
\min\{dp_{i, j - 1} + 1, dp_{i - 1, j} + 1, dp_{i - 1, j - 1} + k\}, &Others
\end{cases}
\]
#include <bits/stdc++.h>
#define endl "\n"
#define int long long
using namespace std;
const int N = 2e3 + 5;
string a, b;
int dp[N][N];
signed main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);cin >> a >> b;memset(dp, 0, sizeof dp);for (int i = 0; i <= a.size(); i++) {for (int j = 0; j <= b.size(); j++) {if (i == 0 && j == 0) {dp[i][j] = 0;} else if (i == 0) {dp[i][j] = dp[i][j - 1] + 1;} else if (j == 0) {dp[i][j] = dp[i - 1][j] + 1;} else {dp[i][j] = min(dp[i - 1][j] + 1,min(dp[i][j - 1] + 1,dp[i - 1][j - 1] + (a[i - 1] == b[j - 1] ? 0 : 1)));}}}cout << dp[a.size()][b.size()] << endl;return 0;
}