• Keywords Search HDU


    求一个字符串上有多少个匹配的单词

    看着卿学姐的板子写的

    指针形式:

    #include <iostream>
    #include <cstdio>
    #include <sstream>
    #include <cstring>
    #include <map>
    #include <set>
    #include <vector>
    #include <stack>
    #include <queue>
    #include <algorithm>
    #include <cmath>
    #define rap(i, a, n) for(int i=a; i<=n; i++)
    #define rep(i, a, n) for(int i=a; i<n; i++)
    #define lap(i, a, n) for(int i=n; i>=a; i--)
    #define lep(i, a, n) for(int i=n; i>a; i--)
    #define MOD 2018
    #define LL long long
    #define ULL unsigned long long
    #define Pair pair<int, int>
    #define mem(a, b) memset(a, b, sizeof(a))
    #define _  ios_base::sync_with_stdio(0),cin.tie(0)
    //freopen("1.txt", "r", stdin);
    using namespace std;
    const int maxn = 1000010, maxm = 500005, INF = 0x7fffffff;
    int tot;
    queue<int> q;
    
    struct state
    {
        int next[26];
        int fail, cnt;
    }trie[500005];
    
    
    void init()
    {
        while(!q.empty()) q.pop();
        for(int i=0; i<maxm; i++)
        {
            mem(trie[i].next, 0);
            trie[i].fail = trie[i].cnt = 0;
        }
        tot = 0;
    }
    
    void insert(char *s)
    {
        int  n = strlen(s);
        int rt = 0;
        for(int i=0;i<n; i++)
        {
            int x = s[i] - 'a';
            if(!trie[rt].next[x])
            {
                trie[rt].next[x] = ++tot;
            }
            rt = trie[rt].next[x];
        }
        trie[rt].cnt++;
    }
    
    void build()
    {
        trie[0].fail= -1;
        q.push(0);
        while(!q.empty())
        {
            int u = q.front(); q.pop();
            for(int i=0; i<26; i++)
            {
                if(trie[u].next[i])
                {
                    if(u == 0) trie[trie[u].next[i]].fail  = 0;
                    else{
                        int v = trie[u].fail;
                        while(v != -1)
                        {
                            if(trie[v].next[i])
                            {
                                trie[trie[u].next[i]].fail = trie[v].next[i];
                                break;
                            }
                            v = trie[v].fail;
                        }
                        if(v == -1) trie[trie[u].next[i]].fail = 0;
                    }
                    q.push(trie[u].next[i]);
                }
            }
        }
    }
    
    int Get(int u)
    {
        int res = 0;
        while(u)
        {
            res = res + trie[u].cnt;
            trie[u].cnt = 0;
            u = trie[u].fail;
        }
        return res;
    }
    
    
    
    int math(char *s)
    {
        int n = strlen(s);
        int rt = 0, res = 0;
        for(int i=0; i<n; i++)
        {
            int x = s[i] - 'a';
            if(trie[rt].next[x])    //如果有儿子 就直接下传
                rt = trie[rt].next[x];
            else                    //如果没有  就去fail去找
            {
                int p = trie[rt].fail;
                while(p != -1 && trie[p].next[x] == 0) p = trie[p].fail;
                if(p == -1) rt = 0; //一直没找到 则返回祖结点
                else rt = trie[p].next[x];
            }
            if(trie[rt].cnt)    //如果以这个点为后缀的串还没有被匹配 则匹配
                res = res + Get(rt);
        }
        return res;
    
    }
    
    int T, n;
    char s[maxn];
    int main()
    {
        scanf("%d", &T);
        while(T--)
        {
            init();
            scanf("%d", &n);
            rap(i, 1, n)
            {
                scanf("%s", s);
                insert(s);
            }
            build();
            scanf("%s", s);
            printf("%d
    ", math(s));
        }
        return 0;
    }

    数组形式:

    #include<stdio.h>
    #include<string.h>
    #include<queue>
    #include<string>
    #include<iostream>
    #define maxn 1000010
    using namespace std;
    int n;
        int nxt[maxn][30],fail[maxn],edd[maxn],root,L;//nxt记录节点,在这里edd指针代表以当前节点为字符串尾的字符串个数
        int vis[maxn];
        int newnode()
        {
            for(int i=0;i<26;i++)
                nxt[L][i]=-1;//节点连接的边初始化为-1
            edd[L]=0;
            vis[L]=0;
            return L++;
        }
        void init()
        {
            L=0;
            root=newnode();
        }
    
        void insert(char *str)//trie树的建立
        {
            int l = strlen(str);
            int now=root;
            for(int i=0;i<l;i++)
            {
                int x = str[i] - 'a';
                if(nxt[now][x]==-1)nxt[now][x]=newnode();
                now=nxt[now][x];
            }
            edd[now]++;
        }
        void build()//建立ac自动机
        {
            queue<int> Q;
            for(int i=0;i<26;i++)
            {
                if(nxt[root][i]==-1)nxt[root][i]=root;
                else                                 //若有连边则将节点加入队列 ,并将fail指针指向root
                {
                    fail[nxt[root][i]]=root;
                    Q.push(nxt[root][i]);
                }
            }
            while(!Q.empty())
            {
                int now=Q.front();
                Q.pop();
                for(int i=0;i<26;i++)
                {
                    if(nxt[now][i]==-1)            //若无连边,则将该边指向当前节点fail指针指向的相应字符连接的节点
                        nxt[now][i]=nxt[fail[now]][i];
                    else                            //若有连边,则将儿子节点的fail指针指向当前节点fail指针指向相应字符接的节点
                    {
                        fail[nxt[now][i]]=nxt[fail[now]][i];
                        Q.push(nxt[now][i]); //加入队列继续遍历
                    }
                }
            }
        }
        int query(char str[])
        {
            int l = strlen(str);
            int now=root;
            int res=0;
            for(int i=0;i<l;i++)
            {
                int x = str[i] - 'a';
                now=nxt[now][x];
                int temp=now;
                while(temp!=root&&vis[temp]==0)//根据题目要求改变形式
                {
                    res+=edd[temp];
                    edd[temp]=0;
                    vis[temp]=1;
                    temp=fail[temp];
                }
            }
            return res; //在这里返回的是匹配到的模式串的数量
        }
    char str[maxn];
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            init();
            int ma=0;
            for(int i=0;i<n;i++)
            {
                scanf("%s",str);
                insert(str);
            }
            scanf("%s", str);
            build();
            int sum=query(str);
            printf("%d
    ", sum);
        }
    }
    自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。
  • 相关阅读:
    [POJ 1417] True Liars
    [POJ 2912] Rochambeau
    [NOIP 2010] 关押罪犯
    [BZOJ 3365] Distance Statistics
    【BZOJ 2821】作诗
    【IOI 2011】Race
    【POJ 2828】Buy Tickets
    FATFS 文件系统
    w25q128 优化读写函数
    keil5编译时出现 MDK-Pro middleware is not allowed with this license
  • 原文地址:https://www.cnblogs.com/WTSRUVF/p/9462743.html
Copyright © 2020-2023  润新知