大意不再赘述。
思路:一开始一看题目就知道是有向无环图上的最长路径,但是有一个问题-->建图非常麻烦,一个字符串要经过三次变换,而且要与之前的字符串相比较看是否可以连边,建图这一部分我还没太想清楚,字符串的处理可以用hash来处理,但怎么去建图呢?25000个点额。
于是去网上查了下资料,发现有一个人处理得很巧妙。
即:用一个hash表将所有的字符串存起来,对于当前字符串,直接判断是否可以连边,连边的条件:通过三次变换该字符串A可以得到hash表中的某个字符串B,而且是字典序,这样才能保证是DAG图。
对于该字符串,我们也没必要直接去连边,如果该字符串通过一次变化可以得到它的话,那么直接进行记忆化搜索,这样就省去了建图的难题。
hash函数的选取最好是选用ELHhash,因为效率够快,而且稳定。
#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> using namespace std; typedef unsigned long UL; const int MAXN = 10000003; //果然还是要够大 int first[MAXN]; int next[25010]; int d[25010]; bool vis[25010]; char st[25010][20]; char temp[20]; int n; void init() { n = 0; memset(vis, 0, sizeof(vis)); memset(first, -1, sizeof(first)); } int ELHhash(char *key) { UL h = 0; while(*key) { h = (h<<4) + *key++; UL g = h & 0xf0000000L; if(g) h ^= g>>24; h &= ~g; } return h%MAXN; } int find(char *str) { int h = ELHhash(str); for(int v = first[h]; v != -1; v = next[v]) { if(!strcmp(st[v], str)) return v; } return -1; //没找到 } void insert(int s) { int h = ELHhash(st[s]); next[s] = first[h]; first[h] = s; } void del(char *str, char *temp, int p) { int j = 0; for(int i = 0; str[i]; i++) if(i != p) { temp[j++] = str[i]; } temp[j] = '\0'; } void add(char *str, char *temp, int p, char c) { int j = 0; int len = strlen(str); for(int i = 0; i <= len; i++) { if(i == p) { temp[j++] = c; } temp[j++] = str[i]; } temp[j] = '\0'; } void repl(char *str, char *temp, int p, char c) { int j = 0; for(int i = 0; str[i]; i++) { if(i == p) temp[j++] = c; else temp[j++] = str[i]; } temp[j] = '\0'; } int dp(int s) { if(vis[s]) return d[s]; vis[s] = 1; int &ans = d[s]; ans = 1; int len = strlen(st[s]); for(int i = 0; i <= len; i++) { for(char c = 'a'; c <= 'z'; c++) { add(st[s], temp, i, c); int p = find(temp); if(p != -1 && strcmp(st[s], temp) < 0) { ans = max(ans, dp(p) + 1); } } } for(int i = 0; i < len; i++) { del(st[s], temp, i); int p = find(temp); if(p != -1 && strcmp(st[s], temp) < 0) { ans = max(ans, dp(p) + 1); } } for(int i = 0; i < len; i++) { for(char c = 'a'; c <= 'z'; c++) { repl(st[s], temp, i, c); int p = find(temp); if(p != -1 && strcmp(st[s], temp) < 0) { ans = max(ans, dp(p) + 1); } } } return ans; } void read_case() { init(); while(~scanf("%s", st[n])) { insert(n); n++; } } void solve() { read_case(); int ans = 0; for(int i = 0; i < n; i++) { ans = max(ans, dp(i)); } printf("%d\n", ans); } int main() { solve(); return 0; }