• 牛客网暑假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);
        }
    }
  • 相关阅读:
    ListView -————不能不说的秘密
    良好的开端是成功的第一步———构建程序
    你所不知道的windows窗体
    数据库查询终结版2———分组——连接
    数据库的终结版查询————你想知道吗?
    《官神》浏览闲看笔记
    坚信梦想,奋勇前进!____OS小题狂刷2333
    众里寻他千百度,蓦然回首,却见写者优先算法,她在书本寂静处!
    生产消费问题扩展——三个并发进程R,M,P和一个共享的循环缓冲区B的并发控制
    多生产者-多消费者-环形缓冲区问题
  • 原文地址:https://www.cnblogs.com/huangdao/p/10828580.html
Copyright © 2020-2023  润新知