洛谷P2758-编辑距离

一道方程较为简单的dp题,但是实际意义还要去多理解。

题目大意:

\(A\)\(B\) 是两个字符串(\(1 \le |A|, |B| \le 2000\))。
我们要用最少的字符操作次数,将字符串 \(A\) 转换为字符串 \(B\)。这里所说的字符操作共有三种:

  1. 删除一个字符;
  2. 插入一个字符;
  3. 将一个字符改为另一个字符。

\(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;
}

希望能理解我的代码!

posted @ 2025-06-02 09:44  Cai_hy  阅读(21)  评论(0)    收藏  举报