题目链接:https://www.luogu.com.cn/problem/P4407
trie树+爆搜
做法:对所有文本串建树。对于编辑距离要求的三种情况,分四类在trie树上爆搜即可。
#define maxn 200010
struct trie{
int son[maxn][26];
int cnt[maxn];
int idx=0;
map<string,bool> mm;
int vis[maxn];
void insert(string s)
{
mm[s]=1;
int u=0;
for(int i=0;i<s.size();i++)
{
int c=s[i];
if(!son[u][c]) son[u][c]=++idx;
u=son[u][c];
}
cnt[u]++;//有多少个单词是以u结尾的
// cerr<<cnt[u]<<' ';
}
int dfs(string s,int cur,int x,bool change)//字符串 当前trie树上的指针 当前遍历到字符串第x个位置 是否进行改变操作
{
if(x==s.size()&&!vis[cur]&&cnt[cur]&&change)
{
vis[cur]=1;
return cnt[cur];
}//在确定已经匹配上了一个数组才修改vis,否则只是一个前缀
int res=0;
if(son[cur][s[x]])//不用修改
{
res+=dfs(s,son[cur][s[x]],x+1,change);
}
if(change)//已修改但是接下来依然要修改,说明当前串不能统计进入答案,直接返回
{
return res;
}
res+=dfs(s,cur,x+1,1);//删除操作
// cerr<<res<<" ";
for(int i=0;i<26;i++)//插入和修改操作涉及新字符,tire树上当前节点的子节点一个个试过去
{
if(son[cur][i])
{
res+=dfs(s,son[cur][i],x+1,1);//修改操作
res+=dfs(s,son[cur][i],x,1);//插入操作
}
}
return res;
}
int solve(string s)
{
memset(vis,0,sizeof(vis));
if(mm[s]!=0) return -1;//如果是单词就直接输出-1
return dfs(s,0,0,0);
}
}T;
int n,m;
void tonum(string &s)
{
for(int i=0;i<s.size();i++)
{
s[i]-='a';
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
string s;
cin>>s;
tonum(s);
T.insert(s);
}
// cerr<<'\n';
while(m--)
{
string s;
cin>>s;
tonum(s);
cout<<T.solve(s)<<'\n';
}
}
标签:int,JSOI2009,trie,电子字典,maxn,tonum,P4407
From: https://www.cnblogs.com/captainfly/p/18181664