[LGP2758]编辑距离
题目
题目描述
设A和B是两个字符串。我们要用最少的字符操作次数,将字符串A转换为字符串B。这里所说的字符操作共有三种:
1、删除一个字符;
2、插入一个字符;
3、将一个字符改为另一个字符;
!皆为小写字母!
输入格式
第一行为字符串A;第二行为字符串B;字符串A和B的长度均小于2000。
输出格式
只有一个正整数,为最少字符操作次数。
输入输出样例
输入 #1
sfdqxbw
gfdgw
输出 #1
4
题目分析
当前的状态会影响到后续的状态。
我们可以考虑DP
设\(dp_{i,j}\)表示把\(a_{1\dots i}\) 转换为\(b_{1\dots j}\)需要的最少步数
那么\(dp_{i,j}\)应该就由四种状态转移过来:立改废存
- 什么都不变
这样需要\(a_i=b_j\),然后直接\(dp_{i,j}=dp_{i-1,j-1}\),也就是直接接下来就可以了
- 插入操作之后得到
那么就应该是让\(a_{1\dots i}\)操作得到\(b_{1\dots j-1}\),那么只需要在\(a_i\)后面插入\(b_j\),就可以把\(a_i\)转换成\(b_{j-1}\)之后再加一步,即\(dp_{i,j}=dp_{i,j-1}+1\)就可以得到\(b_{j}\)
- 删除操作之后得到
就应该让\(a_{1\dots i-1}\)操作之后得到\(b_{1\dots j}\),然后再把\(a_i\)删掉,就能通过\(a_i\)得到\(b_j\),即\(dp_{i,j}=dp_{i-1,j}+1\)
- 替换操作之后得到
那么就是\(a_{i-1}\)操作之后得到\(b_{j-1}\),然后把\(a_i\)改成\(b_j\),前提是\(a_i\neq b_j\),即\(dp_{i,j}=dp_{i-1,j-1}+1\)
如果\(a_i=b_j\),那么就直接接下来,否则就剩下三种情况的最小值。
状态转移方程
初始状态
可以知道初始状态应该是\(dp_{i,0}\)和\(dp_{0,j}\)
也很容易得到把\(a_{1\dots i}\) 变成0(没有串)需要删除\(i\)步
同样\(dp_{0,j}=j\)
结束状态
\(dp_{lena,lenb}\)
Code
#include <cstdio>
#include <cstring>
#include <iostream>
int lena,lenb;
char a[2001],b[2001];
int dp[2001][2001];
int main()
{
scanf("%s%s",a+1,b+1);
lena=strlen(a+1); lenb=strlen(b+1);
for(register int i=1;i<=lena;++i)
{
dp[i][0]=i;
for(register int j=1;j<=lenb;++j)
{
dp[0][j]=j;
if(a[i]==b[j]) dp[i][j]=dp[i-1][j-1]; else
{
dp[i][j]=std::min(std::min(dp[i][j-1],dp[i-1][j]),dp[i-1][j-1])+1;
}
}
}
printf("%d\n",dp[lena][lenb]);
return 0;
}