P4407 [JSOI2009] 电子字典

题目链接: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';
    }

}
posted @ 2024-05-09 10:59  Captainfly19  阅读(6)  评论(0编辑  收藏  举报