洛谷 P2453 [SDOI2006]最短距离
Description
Solution
乍一看,感觉还是挺难的,其实没有那么难,就是一个很暴力的 \(dp\)(我也不知道为什么有状压的标签)。
先定义一下 \(dp\) 状态:设 \(dp[i][j]\) 表示目标串完成到第 \(i\) 个字符,源串删除到第 \(j\) 个字符。
初始值:
\(dp[0][j] = cost_{delete} * j\)
\(dp[i][0] = cost_{insert} * i\)
嗯,很显然。
下面我们来分析一下每个操作。
insert
插入操作:\(dp[i][j] = min(dp[i][j], dp[i - 1][j] + cost_{insert})\)
不需要进行判断。
delete
删除操作;\(dp[i][j] = min(dp[i][j], dp[i][j - 1] + cost_{delete}\)
很容易想到吧,且这个操作同样无需判断。
replace
替换操作:\(dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + cost_{replace})\)
顾名思义,都要进行替换了,还判断什么呢?
copy
复制操作:\(dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + cost_{copy})\)
这个就需要进行判断了,当源串 \(x_j\) 等于目标串 \(y_i\) 时,才能进行转移。
twiddle
交换并复制,这个就有点麻烦了。
先判断,当 \(i\) 和 \(j\) 都大于 1,且 \(x_j == y_{i - 1}\) && \(y_i == x_{j - 1}\)时,才能进行转移。
转移方程:\(dp[i][j] = min(dp[i][j], dp[i - 2][j - 2] + cost_{twiddle})\)
kill
删除一段字符。
这个怎么转移呢?
很简单,单独拎出来就好了。
最后再枚举一遍源串,然后对 \(dp[leny][i] + cost_{kill}\) 取个 \(min\) 即可。
输出的时候再和 \(dp[leny][lenx]\) 取较小值输出。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
char a[1010], b[1010];
int del, rep, cop, ins, twi;
int dp[210][210];
int main(){
scanf("%s%s", a + 1, b + 1);
int la = strlen(a + 1);
int lb = strlen(b + 1);
scanf("%d%d%d%d%d", &del, &rep, &cop, &ins, &twi);
memset(dp, 127, sizeof(dp));
dp[0][0] = 0;
for(int i = 1; i <= la; i++)
dp[0][i] = del * i;
for(int i = 1; i <= lb; i++)
dp[i][0] = ins * i;
for(int i = 1; i <= lb; i++)
for(int j = 1; j <= la; j++){
dp[i][j] = min(dp[i][j], dp[i][j - 1] + del);
dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + rep);
if(a[j] == b[i])
dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + cop);
dp[i][j] = min(dp[i][j], dp[i - 1][j] + ins);
if(i > 1 && j > 1 && a[j] == b[i - 1] && b[i] == a[j - 1])
dp[i][j] = min(dp[i][j], dp[i - 2][j - 2] + twi);
}
int ans = 0x7fffffff;
for (int i = 1; i < la; i++)
ans = min(ans, dp[lb][i] + (la - i) * del - 1);
ans = min(ans, dp[lb][la]);
printf("%d\n", ans);
return 0;
}
End
本文来自博客园,作者:{xixike},转载请注明原文链接:https://www.cnblogs.com/xixike/p/15168082.html
原文地址:https://www.cnblogs.com/xixike/p/15168082.html
- 【LEETCODE】模拟面试-46. Permutations
- CentOS6 Upgrade Python
- Emacs setup for Go Development
- 【LEETCODE】模拟面试-39. Combination Sum
- Docker系列教程12-使用Maven插件构建Docker镜像
- Linux nohup 用法
- 【LEETCODE】模拟面试-84-Largest Rectangle in Histogram
- Docker系列教程11-使用Nexus管理Docker镜像
- Mac 配置终端环境
- 【LEETCODE】模拟面试-101-Symmetric Tree
- Docker系列教程10-使用Docker Registry管理镜像
- webapp开发调试环境--weinre配置
- AWK 深入浅出教程
- Docker系列教程09-使用Docker Hub管理镜像
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- django这些查询技巧你会了吗?
- 手把手教你配置vim,小白也可以
- 【NPM库】- 0x02
- 最长有效括号
- 统计全为1的子矩形
- Android Camera1中的人脸检测
- Executors功能如此强大,ThreadPoolExecutor功不可没(一)
- dotNET:怎样处理程序中的异常(实战篇)?
- 二维背包问题
- 小程序系列之禁用视频快进
- springBoot整合Mq报错:JmsMessagingTemplate that could not be found
- TCP:测试小工具TCPing
- 对象实例化内存布局与访问定位 Krains 2020-08-14
- 基于Docker Compose部署分布式MinIO集群
- Go语言 | 从并发模式看channel使用技巧