Codeforces Beta Round #52 (Div. 2) D. Changing a String DP输出方案

https://codeforces.com/contest/56/problem/D

  • 就是编辑距离的加强版,需要输出方案,那么状态转移方程应该比较常规了,设 d p [ i ] [ j ] dp[i][j] dp[i][j]表示 s s s的前 i i i个字符变成 t t t的前 j j j个字符所需要的最少操作次数,那么 d p [ i ] [ 0 ] , d p [ 0 ] [ j ] , d p [ 0 ] [ 0 ] dp[i][0],dp[0][j],dp[0][0] dp[i][0],dp[0][j],dp[0][0]作为初始状态,容易列出状态转移方程为 d p [ i ] [ j ] = m i n { d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − 1 ] , d p [ i ] [ j − 1 ] } + 1 , ( s [ i ] = t [ j ] ) d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] , ( s [ i ] ≠ t [ j ] ) dp[i][j]=min\{dp[i-1][j],dp[i-1][j-1],dp[i][j-1]\}+1,(s[i]=t[j])\\dp[i][j]=dp[i-1][j-1],(s[i]\neq t[j]) dp[i][j]=min{dp[i1][j],dp[i1][j1],dp[i][j1]}+1,(s[i]=t[j])dp[i][j]=dp[i1][j1],(s[i]=t[j])
  • 重点说一下怎么输出方案,其实就是背包的输出方式,倒序输出,看 d p [ i ] [ j ] dp[i][j] dp[i][j]是从哪个状态转移过来的,比方说从 d p [ i − 1 ] [ j ] dp[i-1][j] dp[i1][j]转移过来,那么这一次所做的操作实际上是删除字符,因为 s s s的前 i − 1 i-1 i1个字符和 t t t的前 j j j个字符已经匹配,那么只能把第 i i i个字符删掉,这样才能保证对于 t t t的前 j j j个字符能够完成匹配
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int INF = 0x3f3f3f3f;
int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  string s, t;
  cin >> s;
  cin >> t;
  int n = s.length();
  int m = t.length();
  vector<vector<int> > dp(n + 1, vector<int>(m + 1));
  for(int i=1;i<=n;i++) dp[i][0] = i;
  for(int j=1;j<=m;j++) dp[0][j] = j;
  dp[0][0] = 0;
  for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
      if(s[i - 1] != t[j - 1]) dp[i][j] = min({dp[i - 1][j], dp[i - 1][j - 1], dp[i][j - 1]}) + 1;
      else dp[i][j] = dp[i - 1][j - 1];
    }
  }
  cout << dp[n][m] << '\n';
  while(n > 0 || m > 0){
    if(m > 0 && n > 0 && dp[n][m] == dp[n - 1][m - 1] + 1){// 替换
      cout << "REPLACE" << ' ' << n << ' ' << t[m - 1] << '\n';
      n -= 1;
      m -= 1;
      continue;
    }
    if(m > 0 && dp[n][m] == dp[n][m - 1] + 1){// 插入,相当于s的前n个字符和t的前m-1个字符匹配,需要插入一个字符到s的第n个位置 才能和t的前m个字符匹配
      cout << "INSERT" << ' ' << n + 1 << ' ' << t[m - 1] << '\n';// 这里n从0开始
      m -= 1;
      continue;
    }
    if(n > 0 && dp[n][m] == dp[n - 1][m] + 1){
      cout << "DELETE" << ' ' << n << '\n';
      n -= 1;
      continue;
    }
    n -= 1;
    m -= 1;
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Clarence Liu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值