P2758 编辑距离 详解

[原题传送门]

请你认认真真看完题目并思考,再参考蒟蒻的题解。


思考过程

个人认为,这道题的正解是区间DP吧,当然各路大佬的神奇做法也很好

好的,这道题如果用区间DP做,应该思考什么呢?

答案非常明确,就是DP的数组表示什么、动态转移方程怎么写。


数组

DP的数组比较容易得到。题目中要求输出的是最少字符操作次数,

DP的题目有个大的特点:题目问什么就设什么。

所以我们可以设一个二维数组f,f[i][j]表示把字符串A的前i个字符变成字符串B的前j个字符所需的最少字符操作次数。

其实,设定数组的经验往往可以通过刷题刷出来。


目标

我们设A的长度为lena,B的长度为lenb。

由数组的定义可知,我们的目标是f[lena][lenb],

即把A全部变成B所需的最少操作数。


动态转移方程

动态转移方程要倒着考虑,要想f[i][j]是由什么推出来的。

由此,我们要分类讨论。

1. 如果A[i]与B[j]相等,就说明让A[i]==B[j]是不用操作的,

所以 f[i][j]=min(f[i][j],f[i-1][j-1])

2. 如果A[i]与B[j]不等,那么使A[i]==B[j]相等需要一步,

f[i][j]可以在f[i-1][j]的基础上插入A[i],需要一次操作;

f[i][j]可以在f[i][j-1]的基础上插入B[j],需要一次操作;

f[i][j]可以在f[i-1][j-1]的基础上把A[i]替换成B[j],需要一次操作。

于是动态转移方程就出来了:

f[i][j]=Min(f[i][j],f[i-1][j-1]+1,f[i-1][j]+1,f[i][j-1]+1);

为了简化码风,可以写成这样:

f[i][j]=Min(f[i][j],f[i-1][j-1],f[i-1][j],f[i][j-1])+1;

好像看起来也没有简洁多少……


初始化

因为要求最小操作次数,所以将f赋值以一个很大的数,

然而,如果仅仅这样,你会发现答案会是一个很大的数。

那是因为我们没有考虑特殊值。

那么有哪些特殊值呢?

就是把一个字符串的前i个字符变成另一个字符串的前1个字符所需的操作数是i。

原因是可以把[2,i]区间内每个数都删除,用了i-1个操作,

再把第一个字符替换为另一个字符串的第一个字符,用了1次操作。

合计i次操作。

1 for(int i=1;i<=lena;i++)
2   f[i][1]=i;
3 for(int i=1;i<=lenb;i++)
4   f[1][i]=i;

Code:

为了让大家方便查看,贴上高清无注释的代码,在过程中我讲解得很详细了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 char a[2005],b[2005];
 4 
 5 int f[2005][2005];
 6 int lena,lenb;
 7 int Min(int a1,int a2,int a3,int a4)
 8 {
 9     a1=min(a1,a2);
10     a1=min(a1,a3);
11     a1=min(a1,a4);
12     return a1;
13 }
14 int main()
15 {
16     memset(f,0x3f3f3f3f,sizeof(f));
17     scanf("%s%s",a+1,b+1);
18 
19     lena=strlen(a+1);
20     lenb=strlen(b+1);
21 
22     for(int i=1;i<=lena;i++)
23         f[i][1]=i;
24     for(int i=1;i<=lenb;i++)
25         f[1][i]=i;
26     for(int i=1;i<=lena;i++)
27         for(int j=1;j<=lenb;j++)
28 
29         {
30             if(a[i]==b[j])
31 
32                 f[i][j]=min(f[i][j],f[i-1][j-1]);
33 
34             else f[i][j]=Min(f[i][j],f[i-1][j-1],f[i-1][j],f[i][j-1])+1;
35 
36         }
37     cout<<f[lena][lenb]-1<<endl;
38     return 0;
39 }

总结

要想练好DP就要多刷题,DP算法代码虽然不长,但是非常难想。

这也是DP学不好的OIer不能成为大佬的原因。

DP的题目尽量要自己推动态转移方程。

希望大家能有所收获!

猜你喜欢

转载自www.cnblogs.com/chengyurui/p/11254016.html