Edit Step Ladders - UVA 10029
题意
题目链接(Virtual Judge):Edit Step Ladders - UVA 10029
题意:
如果单词 \(x\) 能通过添加、删除或修改一个字母变换为单词 \(y\),则称单词 \(x\) 到单词 \(y\) 的变换为一个 edit step。
Edit step ladder 指的是一个按字典序排列的单词序列 \(w_1,w_2,\ldots,w_n\),每个 \(w_{i+1}\) 都由 \(w_i\) 经一个 edit step 变换而来。
给出一个按字典序排列的单词序列,问其中符合 edit step ladder 要求的最长子序列的长度。
思路
虽然这题目又是字典序,又是子序列什么的,但其实跟字符串没多少关系,做法是建图跑最长路,将单词视为图节点,单词之间的变换视为有向边。想出建图这个思路后,剩下的就好办了。
首先是怎样建图的问题。如果采用枚举所有单词对的方法,时间复杂度 \(O(n^2)\),很可能会超时。我们注意到单词的长度非常短,所以不妨换一种思路:对于一个单词,枚举它能变换出的所有单词,这样便能实现 \(O(n)\) 建图。
具体做法如下:用哈希表保存单词及其对应下标。对于一个单词,枚举它经过一步 edit step 变换后的所有单词,看变换后在不在哈希表里。如果在,且下标大于当前单词(为了满足字典序要求),则构造一条有向边。
接着是怎样求解最长路的问题。显然此图是个有向无环图,所以我们可以用动态规划的方法 \(O(n)\) 求出最长路。
用 \(\mathrm{step}(u)\) 表示从 \(u\) 出发的最长路的长度(路径上的节点数),状态转移方程如下:
\begin{array}{ll}
1 & \text{if}\; u \;\text{is a leaf} \\
1+\max\{\mathrm{step}(v) \mid (u,v)\in E\} & \text{otherwise} \\
\end{array}
\right.
\]
代码
注意:输出答案后还要再输出一个换行符,否则 UVA 会判你 WA(而不是 PE),非常的毒瘤。
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <cassert>
using namespace std;
const int maxn = int(25000 + 5);
string word_arr[maxn];
unordered_map<string, int> word_dict;
vector<int> G[maxn];
int step_arr[maxn];
// 将 s 的第 i 个字符换成 ch
string change_letter(const string &s, int i, char ch)
{
string ret = s;
ret[i] = ch;
return ret;
}
// 将 s 的第 i 个字符移除
string remove_letter(const string &s, int i)
{
string ret;
int len = int(s.length());
ret.reserve(len - 1);
for (int j = 0; j < len; j++)
if (j != i)
ret.push_back(s[j]);
return ret;
}
// 在 s 的第 i 个字符前面插入字符 ch
string insert_letter(const string &s, int i, char ch)
{
string ret;
int len = int(s.length());
ret.reserve(len + 1);
if (i == len)
{
ret = s;
ret.push_back(ch);
return ret;
}
for (int j = 0; j < len; j++)
{
if (j == i)
ret.push_back(ch);
ret.push_back(s[j]);
}
return ret;
}
// 添加有向边 u -> v
void add_edge(int u, int v)
{
G[u].push_back(v);
}
// 从点 u 出发的最长路的长度
int longest_step(int u)
{
if (step_arr[u] > 0)
return step_arr[u];
int max_son_step = 0;
for (int v : G[u])
max_son_step = max(max_son_step, longest_step(v));
step_arr[u] = max_son_step + 1;
return step_arr[u];
}
int main()
{
ios_base::sync_with_stdio(false);
string word;
int index = 1;
while (cin >> word)
{
word_arr[index] = word;
word_dict[word] = index;
index++;
}
int n = index - 1;
for (int u = 1; u <= n; u++)
{
const string &cur = word_arr[u];
int len = int(cur.length());
// 修改字符
for (int i = 0; i < len; i++)
{
for (char ch = cur[i] + 1; ch <= 'z'; ch++)
{
string gen = change_letter(cur, i, ch);
if (word_dict.count(gen) > 0)
{
int v = word_dict[gen];
assert(u < v);
add_edge(u, v);
}
}
}
// 移除字符
for (int i = 0; i < len; i++)
{
string gen = remove_letter(cur, i);
if (word_dict.count(gen) > 0)
{
int v = word_dict[gen];
if (u < v)
add_edge(u, v);
}
}
// 插入字符
for (int i = 0; i <= len; i++)
{
for (char ch = 'a'; ch <= 'z'; ch++)
{
string gen = insert_letter(cur, i, ch);
if (word_dict.count(gen) > 0)
{
int v = word_dict[gen];
if (u < v)
add_edge(u, v);
}
}
}
}
int ans = 0;
for (int u = 1; u <= n; u++)
ans = max(ans, longest_step(u));
cout << ans << '\n';
return 0;
}
Edit Step Ladders - UVA 10029的更多相关文章
- UVA - 10029 Edit Step Ladders (二分+hash)
Description Problem C: Edit Step Ladders An edit step is a transformation from one word x to another ...
- UVa 10029 - Edit Step Ladders
題目:已知一些字典序排列的單詞,問能從中找到最大的一個有序單詞集合, 使得集合中的單詞每一個是有上一個單詞經過一次變換得來的(增.刪.改). 分析:dp,LIS.最大遞增子序列,不過數據較大须要優化. ...
- UVA 10029 Edit Step Ladders ——(DAG求最长路)
题意:升序的给出一本若干个单词,每个单词都可删除一个字母,添加一个字母或者改变一个字母,如果任意一个操作以后能变成另外一个字典中的单词,那么就连一条有向边,求最长的长度. 分析:DAG的最长路和最短路 ...
- uva 10026 Problem C: Edit Step Ladders
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&p ...
- POJ2564:Edit Step Ladders
浅谈\(Trie\):https://www.cnblogs.com/AKMer/p/10444829.html 题目传送门:http://poj.org/problem?id=2564 记\(f[i ...
- UVa 10029 hash + dp
题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- ACM训练计划step 1 [非原创]
(Step1-500题)UVaOJ+算法竞赛入门经典+挑战编程+USACO 下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年到1年半年时间完成 ...
- UVA题目分类
题目 Volume 0. Getting Started 开始10055 - Hashmat the Brave Warrior 10071 - Back to High School Physics ...
- (Step1-500题)UVaOJ+算法竞赛入门经典+挑战编程+USACO
http://www.cnblogs.com/sxiszero/p/3618737.html 下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年 ...
随机推荐
- Flink 保证ExactlyOnce
Flink 保证 ExactlyOnce 1.使用执行ExactlyOnce 的数据源,比如 kafka 2.使用FlinkConsumer,开启CheckPointing,偏移量会保存通过Check ...
- opencv入门系列教学(二)图像入门:读取、展示并保存视频
一.从相机读取视频 通常情况下,我们必须用摄像机捕捉实时画面.让我们从摄像头捕捉一段视频(我使用的是我笔记本电脑内置的网络摄像头) ,将其转换成灰度视频并显示出来. 要捕获视频,我们需要 ...
- vue之 分页封装
npm 下载 npm i element-ui -S components 创建 Page 文件夹 创建 Page.vue 文件 vue 文件 <template> <div c ...
- Object-源码
Object的结构 类构造器 一个类必须要有一个构造器的存在 , Object类源码中,是看不到构造器的,系统会自动添加一个无参构造器. Object obj = new Object(): equa ...
- 这些解决 Bug 的套路,你都会了不?
最近整理了我原创的 140 篇编程经验和技术文章,欢迎大家阅读,一起成长!指路:https://t.1yb.co/ARnD 大家好,我是鱼皮. 学编程的过程中,我们会遇到各式各样的 Bug,也常常因为 ...
- SQL语句分组获取记录的第一条数据的方法
使用Northwind 数据库 首先查询Employees表 查询结果: city列里面只有5个城市 使用ROW_NUMBER() OVER(PARTITION BY COL1 ORDER BY CO ...
- JetBrains 系列软件汉化包 2017.3-2018.1
JetBrains 系列软件汉化包 关键字: Android Studio 3.0-3.1.3 汉化包 CLion 2018.1-2018.2 汉化包 GoLand 2017.3.2-2018.2 汉 ...
- PHP中操作数据库的预处理语句
今天这篇文章的内容其实也是非常基础的内容,不过在现代化的开发中,大家都使用框架,已经很少人会去自己封装或者经常写底层的数据库操作代码了.所以这回我们就来复习一下数据库中相关扩展中的预处理语句内容. 什 ...
- MySql WorkBench通过表生成表关系图
1.mysql workbench 菜单file=>add model(添加模型) 点击上面的add diagram(添加新的图解),就会在右边多出一个新的图解模型 2,mysql workbe ...
- redis连接密码和指定数据库
台服务器上都快开启200个redis实例了,看着就崩溃了.这么做无非就是想让不同类型的数据属于不同的应用程序而彼此分开. 那么,redis有没有什么方法使不同的应用程序数据彼此分开同时又存储在相同的实 ...