浅谈(Trie):https://www.cnblogs.com/AKMer/p/10444829.html
题目传送门:http://poj.org/problem?id=2564
记(f[i])表示从第(i)个字符串开始可以变换多长。
每次把当前字符串在(Trie)树上搜索,设(dp(ID,u,len,bo))表示我把第(ID)个字符串在(Trie)树上搜索,到了(u)这个点,已经处理了(len)位,并且是否做过改动。
修改就走除了下一个字符以外的边继续搜,插入就枚举(26)条边依次去搜但是不加(len),删除就是再次访问当前节点不过让(len=len+1)
当(len)等于字符串长度的时候和当前点表示的那一号字符串的(f_{u}+1)取(max)即可。
答案就是(f)的最大值加一。
时间复杂度:(O(n*len^2*26))
空间复杂度:(O(n*len*26))
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=25005;
int n=1,ans;
char s[maxn][20];
int f[maxn],Len[maxn];
struct Trie {
int tot;
int id[maxn*16];
int son[maxn*16][26];
void ins(int ID) {
int pos=1,len=strlen(s[ID]+1);
for(int i=1;i<=len;i++) {
if(son[pos][s[ID][i]-'a'])
pos=son[pos][s[ID][i]-'a'];
else pos=son[pos][s[ID][i]-'a']=++tot;
}
id[pos]=ID;
}
void dp(int ID,int u,int len,int bo) {
if(len==Len[ID]) {
if(id[u]&&bo)return;
if(id[u])f[ID]=max(f[ID],f[id[u]]+1);
if(bo) {
for(int i=0;i<26;i++)
if(id[son[u][i]])f[ID]=max(f[ID],f[id[son[u][i]]]+1);
}
return;
}
int c=s[ID][len+1]-'a';
if(son[u][c])dp(ID,son[u][c],len+1,bo);
if(bo) {
for(int i=0;i<26;i++) {
dp(ID,son[u][i],len,0);
if(i!=c)dp(ID,son[u][i],len+1,0);
}
dp(ID,u,len+1,0);
}
}
}T;
int main() {
T.tot=1;
while(~scanf("%s",s[n]+1))n++;
for(int i=1;i<n;i++) {
Len[i]=strlen(s[i]+1),T.dp(i,1,0,1);
ans=max(ans,f[i]),T.ins(i);
}
printf("%d
",ans+1);
return 0;
}