洛谷P2758-编辑距离
一道方程较为简单的dp题,但是实际意义还要去多理解。
题目大意:
设 \(A\) 和 \(B\) 是两个字符串(\(1 \le |A|, |B| \le 2000\))。
我们要用最少的字符操作次数,将字符串 \(A\) 转换为字符串 \(B\)。这里所说的字符操作共有三种:
- 删除一个字符;
- 插入一个字符;
- 将一个字符改为另一个字符。
\(A, B\) 均只包含小写字母。
注:字符操作仅能在字符串 \(A\) 上进行.
题目思路:
这道题最终的目的是求出转化为字符串 \(B\) 所需的最少操作次数,
作为一道dp题,需要求出最终状态时一般从初始状态开始枚举.
假设现在建立一个数组 \(dp[i][j]\) 表示A的前i位转化为B的前j位所需的最少操作次数。
那么,如何去求出它呢?
动态规划的状态间可以通过转移得来。不妨思考一下 \(dp[i][j]\) 的前置状态是什么?
- 删除- \(dp[i-1][j]+1\) :因为 \(dp[i-1][j]\) 的定义为A的前i-1位转为B的前j位,所以
当现在多出了A的第i位时,把这多出的删除。每个操作都计数一次.
dp数组的定义只记录了一个值,不管操作怎么样,只要符合(数组的)定义就可以了.
-
添加- \(dp[i][j-1]+1\) :A的前i位已经转为了B的前j-1位,所以当现在多出了B的第i位时,
A此时就少了一位,所以要添加. -
转换&不变- \(dp[i-1][j-1]+(1/0)\) : 假设A的前i-1位已经转为了B的前j-1位,那么此时多出来的
A的第i位与B的第j位想要做到相等,就要把Ai替换为Bj。此时就分出了转换和不变两种情况。
如果两个字母相等,就不用转化,否则就把 \(A_i\) 改为 \(B_j\) .
每一个 \(dp[i][j]\) 都可以由这几种前继状态转换得来,此时就应该取其中的最小值。此时,dp方程已经求出,便是:
\[dp[i][j]\;=\;min(dp[i][j-1]+1,dp[i-1][j]+1,dp[i-1][j-1]+(1/0))
\]
注意i和j最开始应从字符串的起始枚举,否则后面的计算没有前继的数据会导致计算错误.
\(代码:\)
#include<bits/stdc++.h>
using namespace std;
int dp[2005][2005],lena,lenb;
string a,b;
int main(){
cin >> a >> b;
lena = a.length();lenb = b.length();
for(int i = 1;i <= lena;i++) dp[i][0] = i; //预处理,此时的操作应把A全部删除
for(int i = 1;i <= lenb;i++) dp[0][i] = i; //同理,在A添加i个字符与B相等
for(int i = 1;i <= lena;i++){
for(int j = 1;j <= lenb;j++){
dp[i][j] = min(min(dp[i - 1][j] + 1,dp[i][j - 1] + 1),dp[i - 1][j - 1] + (a[i - 1] != b[j - 1]));
}
}
cout<<dp[lena][lenb];
return 0;
}
希望能理解我的代码!

浙公网安备 33010602011771号