大意不再赘述。
思路:一开始一看题目就知道是有向无环图上的最长路径,但是有一个问题-->建图非常麻烦,一个字符串要经过三次变换,而且要与之前的字符串相比较看是否可以连边,建图这一部分我还没太想清楚,字符串的处理可以用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;
}
本文介绍了一种高效处理复杂字符串匹配问题的方法,通过使用哈希表存储所有字符串并判断是否可以建立边,避免了传统建图过程中的繁琐操作。通过ELH哈希函数优化字符串处理,实现记忆化搜索,有效解决了大规模点集上的最长路径问题。
1128

被折叠的 条评论
为什么被折叠?



