zoukankan      html  css  js  c++  java
  • AC自动机学习笔记

    原博客地址:https://www.cnblogs.com/hyfhaha/p/10802604.html

    问题的背景

    来一道题:

    给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。

    注意:是出现过,就是出现多次只算一次。

    img

    我们将n个模式串建成一颗字典树。但是当我们匹配成功一个模式串后,需要重新回到根做匹配,这样效率太低了。

    比如这个字典树,我们从4号点匹配失败后,可以继续从7号点开始匹配,然后匹配到8。

    那么我们怎么确定从哪个点开始匹配呢?我们称i匹配失败后从j开始匹配,j是i的失配指针。

    失配指针的实质含义是什么?

    如果一个点的Fail指针指向j,那么root到j的字符串是root到i的字符串的一个后缀。

    所以Fail指针的含义是:最长的当前字符串的后缀在字典树上可以找到的末尾编号。

    求Fail指针

    首先我们可以确定,每一个点i的Fail指针指向的点的深度一定是比i小的。

    第一层的Fail一定指的是root。

    设点i的父亲fa的Fail指针指的是Fafail,那么如果Fafail有和i值相同的儿子j,那么i的Fail就指向j。(此时我已经懵逼)

    具体实现:

    void getFail () {
        for (int i=0;i<26;i++) Trie[0].son[i]=1;
        queue<int> q;
        q.push(1);
        Trie[1].fail=0;
        while (!q.empty()) {
            int u=q.front();
            q.pop();
            for (int i=0;i<26;i++) {
                int v=Trie[u].son[i];
                int Fail=Trie[u].fail;
                if (!v) {
                    Trie[u].son[i]=Trie[Fail].son[i];
                    continue;
                }
                Trie[v].fail=Trie[Fail].son[i];
                q.push(v);
            }
        }
    }

    查询

    int query (char * s) {
        int u=1;
        int ans=0;
        int len=strlen(s);
        for (int i=0;i<len;i++) {
            int v=s[i]-'a';
            int k=Trie[u].son[v];
            while (k>1&&Trie[k].f!=-1) {
                ans+=Trie[k].f;
                Trie[k].f=-1;
                k=Trie[k].fail;
            }
            u=Trie[u].son[v];
        }
        return ans;
    }

    完整代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+100;
    struct trie {
        int son[26];
        int f;
        int fail;
    }Trie[maxn];
    int n,cnt;
    char s[maxn];
    queue<int> q;
    void insert (char * s) {
        int u=1;
        int len=strlen(s);
        for (int i=0;i<len;i++) {
            int v=s[i]-'a';
            if (!Trie[u].son[v]) Trie[u].son[v]=++cnt;
            u=Trie[u].son[v];
        }
        Trie[u].f++;
    } 
    void getFail () {
        for (int i=0;i<26;i++) Trie[0].son[i]=1;
        queue<int> q;
        q.push(1);
        Trie[1].fail=0;
        while (!q.empty()) {
            int u=q.front();
            q.pop();
            for (int i=0;i<26;i++) {
                int v=Trie[u].son[i];
                int Fail=Trie[u].fail;
                if (!v) {
                    Trie[u].son[i]=Trie[Fail].son[i];
                    continue;
                }
                Trie[v].fail=Trie[Fail].son[i];
                q.push(v);
            }
        }
    }
    int query (char * s) {
        int u=1;
        int ans=0;
        int len=strlen(s);
        for (int i=0;i<len;i++) {
            int v=s[i]-'a';
            int k=Trie[u].son[v];
            while (k>1&&Trie[k].f!=-1) {
                ans+=Trie[k].f;
                Trie[k].f=-1;
                k=Trie[k].fail;
            }
            u=Trie[u].son[v];
        }
        return ans;
    }
    int main () {
        cnt=1;
        cin>>n;
        for (int i=1;i<=n;i++) scanf("%s",s),insert(s);
        getFail();
        scanf("%s",s);
        printf("%d
    ",query(s));
        return 0;
    }
  • 相关阅读:
    使用 asp.net mvc和 jQuery UI 控件包
    ServiceStack.Redis 使用教程
    HTC T8878刷机手册
    Entity Framework CodeFirst 文章汇集
    2011年Mono发展历程
    日志管理实用程序LogExpert
    使用 NuGet 管理项目库
    WCF 4.0路由服务Routing Service
    精进不休 .NET 4.0 (1) asp.net 4.0 新特性之web.config的改进, ViewStateMode, ClientIDMode, EnablePersistedSelection, 控件的其它一些改进
    精进不休 .NET 4.0 (7) ADO.NET Entity Framework 4.0 新特性
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/13209955.html
Copyright © 2011-2022 走看看