题目大意: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; }
时间: 2024-10-01 06:16:11