题意:给你一串已经按字典序排列好的单词,前一个单词通过增加,删除和替换一个字母这三种操作一个操作变成后一个单词,求最长的序列。
思路:刚开始要建图然后求DAG上的最长路,但图的建立太大了,会TLE的。之后发现可以一边寻找一边判断是否能通过一个操作匹配。其实删除和增加的操作效果是一样的,所以可以分为当单词长度相同和不同是进行判断,而且两个单词之间的长度之差必须<=1。这中方法正好卡着时间过了,2679ms。
网上看了别人的题解,用二分查找前一个单词中是否有匹配的单词,降低时间复杂度。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 25005;
struct String{
char s[20];
int len;
}str[MAXN];
int d[MAXN];
int cnt = 1;
int check(int n, int m) {
int flag = 0;
if (str[n].len == str[m].len) {
for (int i = 0; i < str[n].len; i++) {
if (str[n].s[i] != str[m].s[i]) {
if (flag)
return 0;
else
flag = 1;
}
}
if (flag)
return 1;
}
else if (str[n].len == str[m].len + 1) {
for (int i = 0, j = 0; i < str[n].len; i++) {
if (str[n].s[i] != str[m].s[j]) {
if (flag)
return 0;
else
flag = 1;
continue;
}
j++;
}
if (flag)
return 1;
}
else if (str[n].len == str[m].len - 1) {
for (int i = 0, j = 0; i < str[m].len; i++) {
if (str[n].s[j] != str[m].s[i]) {
if (flag)
return 0;
else
flag = 1;
continue;
}
j++;
}
if (flag)
return 1;
}
else
return 0;
}
int dp() {
int Max = 0;
for (int i = 1; i < cnt; i++) {
d[i] = 1;
for (int j = 1; j < i; j++)
if (check(i, j)) {
d[i] = max(d[i], d[j] + 1);
Max = max(Max, d[i]);
}
}
return Max;
}
int main() {
while (gets(str[cnt].s) != NULL) {
str[cnt].len = strlen(str[cnt].s);
cnt++;
}
memset(d, 0, sizeof(d));
int ans = dp();
printf("%d\n", ans);
return 0;
}