【训练题14:线性DP(经典题)】字串距离 | 洛谷P1279

字串距离 | 洛谷P1279

难度

普 及 + / 提 高 \color{green}普及+/提高 +/
不是很难。
但是是线性DP的经典题,所以写一下 \sqrt{}

题意

  • 扩展串:在原串的基础上,任意位置添加任意多个(或0个)空格之后形成的串。
  • 两个字符串 A 、 B A、B AB字串距离等于某对相同长度的扩展串 A ′ 、 B ′ A^\prime、B^\prime AB 的每一位字符的距离和的最小值。

两个字符的距离:

  • 若是两个小写字母,则距离为他们的 A S C I I ASCII ASCII码的差的绝对值
  • 若一个是空格一个是小写字母,则距离为给定的 k k k
  • 若两个都是空格,则距离为0。

给定两个字符串,求出他们的字串距离。

数据范围

∣ A ∣ , ∣ B ∣ ≤ 2000 |A|,|B|\le 2000 A,B2000
1 ≤ k ≤ 100 1\le k\le 100 1k100

思路

  • 画一下图,可以大概知道在最优情况下,肯定是一些字符配对,剩下的字符都和空格配对,这样才可以使得最后的答案尽可能小。
  • 在这里插入图片描述
  • 这样,我们可能会想到一些线性DP的感觉,数据范围也提示了可以是 O ( ∣ A ∣ × ∣ B ∣ ) O(|A|\times|B|) O(A×B) D P DP DP 做法。
  • 容易想到,我们设 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示 第一个字符串匹配到第 i i i 位,第二个字符串匹配到第 j j j 位所能得到的字串距离
  • 考虑转移。我们有三种简单的选择:
  1. 配对这两个位置的字符。
  2. 第一个串的第 i i i 位的字符和空格匹配。
  3. 第二个串的第 j j j 位的字符和空格匹配
    即:
    d p [ i ] [ j ] = { d p [ i − 1 ] [ j − 1 ] + d i s ( A i , B j ) d p [ i − 1 ] [ j ] + k d p [ i ] [ j − 1 ] + k \color{cyan}dp[i][j]= \begin{cases} dp[i-1][j-1]+dis(A_i,B_j)\\ dp[i-1][j]+k\\ dp[i][j-1]+k \end{cases} dp[i][j]=dp[i1][j1]+dis(Ai,Bj)dp[i1][j]+kdp[i][j1]+k

注意的几个点,字符串尽量让下标从1开始。
初始化 d p [ 0 ] [ j ] dp[0][j] dp[0][j] 以及 d p [ i ] [ 0 ] dp[i][0] dp[i][0] ,因为他们不会自己更新。

核心代码

时间复杂度 O ( ∣ A ∣ × ∣ B ∣ ) O(|A|\times|B|) O(A×B)

/*
 _            __   __          _          _
| |           \ \ / /         | |        (_)
| |__  _   _   \ V /__ _ _ __ | |     ___ _
| '_ \| | | |   \ // _` | '_ \| |    / _ \ |
| |_) | |_| |   | | (_| | | | | |___|  __/ |
|_.__/ \__, |   \_/\__,_|_| |_\_____/\___|_|
        __/ |
       |___/
*/
const int MAX = 2e3+50;
const int INF = 0x3f3f3f3f;

string aa,bb;
int dp[MAX][MAX];
int main()
{
    
    
    int k;
    cin >> aa >> bb >> k;
    fill(dp[0],dp[0] + MAX * MAX,INF);
    aa = " " + aa;
    bb = " " + bb;
    dp[0][0] = 0;
    for(int i = 1;i < aa.size();++i)dp[i][0] = k * i;
    for(int i = 1;i < bb.size();++i)dp[0][i] = k * i;

    for(int i = 1;i < aa.size();++i){
    
    
        for(int j = 1;j < bb.size();++j){
    
    
            dp[i][j] = min(dp[i][j],dp[i-1][j-1] + abs(aa[i] - bb[j]));
            dp[i][j] = min(dp[i][j],dp[i][j-1] + k);
            dp[i][j] = min(dp[i][j],dp[i-1][j] + k);
        }
    }
    cout << dp[aa.size()-1][bb.size()-1];
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45775438/article/details/109851895