|
|
##[$AcWing$ $902$. 最短编辑距离](https://www.acwing.com/problem/content/description/904/)
|
|
|
|
|
|
### 一、题目描述
|
|
|
给定两个字符串 $A$ 和 $B$,现在要将 $A$ 经过若干操作变为 $B$,可进行的操作有:
|
|
|
|
|
|
1. 删除–将字符串 $A$ 中的某个字符删除。
|
|
|
2. 插入–在字符串 $A$ 的某个位置插入某个字符。
|
|
|
3. 替换–将字符串 $A$ 中的某个字符替换为另一个字符。
|
|
|
|
|
|
现在请你求出,将 $A$ 变为 $B$ 至少需要进行多少次操作。
|
|
|
|
|
|
**输入格式**
|
|
|
第一行包含整数 $n$,表示字符串 $A$ 的长度。
|
|
|
|
|
|
第二行包含一个长度为 $n$ 的字符串 $A$。
|
|
|
|
|
|
第三行包含整数 $m$,表示字符串 $B$ 的长度。
|
|
|
|
|
|
第四行包含一个长度为 $m$ 的字符串 B。
|
|
|
|
|
|
字符串中均只包含大小写字母。
|
|
|
|
|
|
**输出格式**
|
|
|
输出一个整数,表示最少操作次数。
|
|
|
|
|
|
**数据范围**
|
|
|
$1≤n,m≤1000$
|
|
|
|
|
|
**输入样例**:
|
|
|
```cpp {.line-numbers}
|
|
|
10
|
|
|
AGTCTGACGC
|
|
|
11
|
|
|
AGTAAGTAGGC
|
|
|
```
|
|
|
**输出样例**:
|
|
|
```cpp {.line-numbers}
|
|
|
4
|
|
|
```
|
|
|
|
|
|
|
|
|
### 二、解题思路
|
|
|
|
|
|
与$LCS$(最长公共子序列)问题的状态表示是很接近的。
|
|
|
|
|
|

|
|
|
|
|
|
#### 状态表示
|
|
|
|
|
|
$f[i,j]$:$a[1..i]$变成$b[1..j]$的操作步数。
|
|
|
|
|
|
现在要求的是:两个字符串的最短编辑距离,由于我们不知道最短编辑距离是多少,就希望知道 **当前状态是从哪些状态转移过来**,前面的状态可以通过 **增加、删除、修改转移过来** 。
|
|
|
|
|
|
#### 属性
|
|
|
|
|
|
操作数的最小值,$min$。
|
|
|
|
|
|
#### 状态计算
|
|
|
|
|
|
按题意划分为删除,增加,修改,相等四种情况
|
|
|
|
|
|
|
|
|
- 删除:把$a[i]$删掉之后$a[1\sim i]$和$b[1\sim j]$匹配.所以没删除之前,就有$a[1 \sim i-1]$与$b[1 \sim j]$匹配
|
|
|
|
|
|
$$\large f[i][j]=f[i-1][j] + 1$$
|
|
|
|
|
|
- 插入:插入之后$a[i]$与$b[j]$完全匹配,所以插入的就是$b[j]$,那填之前$a[1\sim i]$和$b[1\sim (j-1)]$匹配
|
|
|
$$\large f[i][j]=f[i][j-1] + 1$$
|
|
|
|
|
|
- 替换:把$a[i]$改成$b[j]$之后想要$a[1\sim i]$与$b[1\sim j]$匹配,那么修改这一位之前,$a[1\sim (i-1)]$应该与$b[1\sim (j-1)]$匹配
|
|
|
$$\large f[i][j]=f[i-1][j-1] + 1$$
|
|
|
|
|
|
- 相等:如果本来$a[i]$与$b[j]$这一位上就相等,那么不用改,即
|
|
|
$$\large f[i][j]=f[i-1][j-1]$$
|
|
|
|
|
|
**结论**
|
|
|
|
|
|
$$f[i][j] = min(f[i-1][j]+1,f[i][j-1]+1,f[i-1][j-1]+(a[i] == b[j]?0:1))$$
|
|
|
|
|
|
#### 初始化
|
|
|
|
|
|
细节问题:初始化怎么搞
|
|
|
|
|
|
先考虑有哪些初始化嘛
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
- $f[0][i]$:如果$a$初始长度就是$0$,那么只能用插入操作让它变成$b$
|
|
|
|
|
|
- $f[i][0]$:如果$b$的长度是$0$,那么$a$只能用删除操作让它变成$b$
|
|
|
|
|
|
- $f[i][j]$ = $INF$ 其它初始化为$INF$
|
|
|
|
|
|
### 二、实现代码
|
|
|
|
|
|
```cpp {.line-numbers}
|
|
|
#include <bits/stdc++.h>
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
const int N = 1010;
|
|
|
int n, m;
|
|
|
char a[N], b[N];
|
|
|
int f[N][N];
|
|
|
|
|
|
// 最短编辑距离
|
|
|
int main() {
|
|
|
cin >> n >> a + 1 >> m >> b + 1;
|
|
|
|
|
|
// 初始化
|
|
|
for (int i = 0; i <= m; i++) f[0][i] = i;
|
|
|
for (int i = 0; i <= n; i++) f[i][0] = i;
|
|
|
|
|
|
for (int i = 1; i <= n; i++)
|
|
|
for (int j = 1; j <= m; j++) {
|
|
|
// 增加和删除
|
|
|
f[i][j] = min(f[i - 1][j] + 1, f[i][j - 1] + 1);
|
|
|
// 修改
|
|
|
if (a[i] == b[j])
|
|
|
f[i][j] = min(f[i][j], f[i - 1][j - 1]);
|
|
|
else // 相等
|
|
|
f[i][j] = min(f[i][j], f[i - 1][j - 1] + 1);
|
|
|
}
|
|
|
|
|
|
cout << f[n][m] << endl;
|
|
|
return 0;
|
|
|
}
|
|
|
```
|