题目大意:UVA10029 - Edit Step Ladders(LIS)
题目大意:给你一个按照字典序读入的单词,然后要求你找出最长的序列,要求这个最长的序列也要满足字典序,并且后一个是由前一个单词,由在任意的地方替换,增加,删除一个字符变换来的。
解题思路:LIS。但是这里的O(n^2) 25000,超时。但是查找符合的单词有个规律,符合变换要求的单词的长度是有要求的,必须相差小于等于1.并且数据中相同长度的单词不会超过45个,那么就可以把这些单词按照长度分类,那么查找的时候就是45 * 3.省下很多的时间。然后就是单词变换,这里分替换,和删除(插入是一样的)。这种做法是因为数据的原因,正解应该是将每个单词的变换的可能都变换出来(可以预处理+hash),然后再用二分查询找到是否有对应的单词。少了return,wa了无数次。真的要细心。
代码:
#include <cstdio>
#include <cstring>
const int maxn = 25005;
const int maxnL = 20;
char word[maxn][maxnL];
int n;
int l[maxn];//单词的长度
int dp[maxn];
int kind[maxnL][maxn]; //长度分类
int c[maxnL];
int Max (const int a, const int b) { return a > b? a: b; }
bool j_del (int a, int b) {//处理增加很删除
int flag = 0;
for (int i = 0, j = 0; i < l[b]; i++) {
if (word[b][i] != word[a][j]) {
if (flag)
return false;
else
flag = 1;
continue;
}
j++;
}
if (flag)
return true;
return false;
}
bool judge (int a, int b) {
if (l[a] == l[b]) {//处理替换
int flag = 0;
for (int i = 0; i < l[a]; i++) {
if (word[a][i] != word[b][i]) {
if (flag)
return false;
else
flag = 1;
}
}
if (flag)
return true;
return false;
} else if (l[a] == l[b] + 1)
return j_del(b, a);
else if (l[b] == l[a] + 1)
return j_del(a, b);
else
return false;
}
void search (int len, int i) {
for(int j = 0; j < c[len]; j++)
if(i > kind[len][j] && judge (kind[len][j], i)) {
dp[i] = Max (dp[i], dp[kind[len][j]] + 1);
}
}
void handle () {
for (int i = 1; i < n; i++) {
search (l[i] - 1, i);
search (l[i], i);
search (l[i] + 1, i);
/* for (int j = 1; j < i; j++)
if (judge(j, i))
dp[i] = Max (dp[i], dp[j] + 1);*/
}
}
int main () {
n = 1;
memset (c, 0, sizeof (c));
while (gets(word[n]) != NULL) {
l[n] = strlen (word[n]);
kind[l[n]][c[l[n]]++] = n;
n++;
}
for (int i = 1; i < n; i++)
dp[i] = 1;
handle ();
int ans = 0;
for (int i = 1; i < n; i++)
ans = Max (ans, dp[i]);
printf ("%d\n", ans);
return 0;
}