牛客网暑假ACM多校第九场F-Typing pratice(AC自动机+最短路)

链接

题意:给你n个字符串,再给你一个匹配串,问你对于匹配串的每一个字符,至少在后面添加几个字符,使得之前给的n的字符串中有添加后的串的后缀

解题思路:因为是要当多模式匹配,想到用AC自动机,因为要至少添加几个字符,所以我们把n个给定的字符串存在trie图中,把每个串结尾点标记,从结尾点开始往前bfs,这样可以算到,当前要匹配的字符串在trie图中匹配到某个位置后,至少需要多少步能走到结尾点,具体看代码

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=400500;
const int inf=0x3f3f3f3f;
int trie[maxn][26];
int fail[maxn],tot;
int flag[maxn];
int dist[maxn];
int n;
vector<int>v[maxn];
set<int>s;
char t[maxn];
void init()
{
    memset(trie,0,sizeof(trie));tot=0;
    memset(fail,0,sizeof(fail));
    memset(flag,0,sizeof(flag));
    memset(dist,inf,sizeof(dist));
    s.clear();
}
void build_trie(char *str)
{
    int root=0;
    int len=strlen(str);
    for(int i=0;i<len;i++)
    {
        int id=str[i]-'a';
        if(!trie[root][id])
            trie[root][id]=++tot;
        root=trie[root][id];
    }
    flag[root]=1;s.insert(root);//标记结尾点,存起来,等下bfs时候要从结尾点开始
}
void build_fail()
{
    queue<int>q;
    for(int i=0;i<26;i++)
    {
        if(trie[0][i]!=0)
            q.push(trie[0][i]);
    }
    while(!q.empty())
    {
        int now=q.front();q.pop();
        if(flag[fail[now]])
        {
            flag[now]=1;s.insert(now);//这里重点,如果一个点的fail指向某个结尾点,那么它也是结尾点;fail的定义是指向当前串的最长后缀
        }
        for(int i=0;i<26;i++)
        {
            if(!trie[now][i])
            {
                trie[now][i]=trie[fail[now]][i];
                continue;
            }
            fail[trie[now][i]]=trie[fail[now]][i];
            q.push(trie[now][i]);
        }
    }
}
void bfs()
{
    for(int i=0;i<=tot;i++)
        v[i].clear();
    for(int i=0;i<=tot;i++)
        for(int j=0;j<26;j++)
            v[trie[i][j]].push_back(i);//把trie图反过来存
    queue<int>q;
    for(set<int>::iterator it=s.begin();it!=s.end();it++)
    {
        q.push(*it);dist[*it]=0;//结尾点成开始搜索点
    }
    while(!q.empty())
    {
        int now=q.front();q.pop();
        for(int i=0;i<v[now].size();i++)
        {
            if(dist[v[now][i]]!=inf)continue;
            dist[v[now][i]]=dist[now]+1;
            q.push(v[now][i]);
        }
    }
}
void query(char *str)
{
    int len=strlen(str);
    stack<int>sta;//。因为有减号,用栈存
    int root=0;
    int now=root;//从根节点开始
    cout<<dist[now]<<endl;
    for(int i=0;i<len;i++)
    {
        if(str[i]=='-')
        {
            if(sta.empty())
                now=root;
            else
            {
                now=sta.top();sta.pop();
            }
        }
        else
        {
            sta.push(now);//一路匹配下去
            now=trie[now][str[i]-'a'];
        }
        cout<<dist[now]<<endl;//输出当前答案
    }
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%s",t);build_trie(t);
        }
        build_fail();
        bfs();
        scanf("%s",t);
        query(t);
    }
}

猜你喜欢

转载自www.cnblogs.com/huangdao/p/10828580.html