[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}\)应该就由四种状态转移过来:立改废存

  1. 什么都不变

这样需要\(a_i=b_j\),然后直接\(dp_{i,j}=dp_{i-1,j-1}\),也就是直接接下来就可以了

  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}\)

  1. 删除操作之后得到

就应该让\(a_{1\dots i-1}\)操作之后得到\(b_{1\dots j}\),然后再把\(a_i\)删掉,就能通过\(a_i\)得到\(b_j\),即\(dp_{i,j}=dp_{i-1,j}+1\)

  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,j}= \begin{cases} dp_{i-1,j-1} & a_i=b_j \\ \min(dp_{i-1,j},dp_{i,j-1},dp{i-1,j-1})+1 & a_i \neq b_j \end{cases} \]

初始状态

可以知道初始状态应该是\(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;
}
posted @ 2021-07-29 13:59  IdanSuce  阅读(31)  评论(0编辑  收藏  举报