AC自动机 板子

//ac自动机简单版板子(求有多少个不同的模式串在文本串里出现过)
struct tree
{
    int fail; int vis[26]; int end;
}ac[N];
int cnt = 0;
void add(string s)//将模式串插入字典树
{
    int l = s.length();
    int now = 0;
    for (int i = 0; i < l; i++)
    {
        if (ac[now].vis[s[i] - 'a'] == 0)
            ac[now].vis[s[i] - 'a'] = ++cnt;
        now = ac[now].vis[s[i] - 'a'];
    }
    ac[now].end += 1;
}
void get_fail()//得到fail数组
{
    queue<int>q;
    for (int i = 0; i < 26; i++)
    {
        if (ac[0].vis[i] != 0)
        {
            ac[ac[0].vis[i]].fail = 0;
            q.push(ac[0].vis[i]);
        }
    }
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int i = 0; i < 26; i++)
        {
            if (ac[u].vis[i] != 0)
            {
                ac[ac[u].vis[i]].fail = ac[ac[u].fail].vis[i];
                q.push(ac[u].vis[i]);
            }
            else
            {
                ac[u].vis[i] = ac[ac[u].fail].vis[i];
            }
        }
    }
}
int ac_query(string s)
{
    int l = s.length();
    int now = 0, ans = 0;
    for (int i = 0; i < l; i++)
    {
        now = ac[now].vis[s[i] - 'a'];
        for (int j = now; j && ac[j].end != -1; j = ac[j].fail)
        {
            ans += ac[j].end;
            ac[j].end = -1;
        }
    }
    return ans;
}
int main()
{
    int n = read();
    string s;
    for (int i = 1; i <= n; i++)
    {
        s = sread();
        add(s);
    }
    ac[0].fail = 0;
    get_fail();
    s = sread();
    cout << ac_query(s) << "\n";
    return 0;
}
```

```
//哪些模式串在文本串中出现的次数最多
struct Tree//字典树 
{
    int fail;//失配指针
    int vis[26];//子节点的位置
    int end;//标记以这个节点结尾的单词编号 
}AC[100000];//Trie树
int cnt = 0;//Trie的指针 
struct Result
{
    int num;
    int pos;
}Ans[100000];//所有单词的出现次数 
bool operator <(Result a, Result b)
{
    if (a.num != b.num)
        return a.num > b.num;
    else
        return a.pos < b.pos;
}
string s[100000];
inline void Clean(int x)
{
    memset(AC[x].vis, 0, sizeof(AC[x].vis));
    AC[x].fail = 0;
    AC[x].end = 0;
}
inline void Build(string s, int Num)
{
    int l = s.length();
    int now = 0;//字典树的当前指针 
    for (int i = 0; i < l; ++i)//构造Trie树
    {
        if (AC[now].vis[s[i] - 'a'] == 0)//Trie树没有这个子节点
        {
            AC[now].vis[s[i] - 'a'] = ++cnt;//构造出来
            Clean(cnt);
        }
        now = AC[now].vis[s[i] - 'a'];//向下构造 
    }
    AC[now].end = Num;//标记单词结尾 
}
void Get_fail()//构造fail指针
{
    queue<int> Q;//队列 
    for (int i = 0; i < 26; ++i)//第二层的fail指针提前处理一下
    {
        if (AC[0].vis[i] != 0)
        {
            AC[AC[0].vis[i]].fail = 0;//指向根节点
            Q.push(AC[0].vis[i]);//压入队列 
        }
    }
    while (!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        for (int i = 0; i < 26; ++i)
        {
            if (AC[u].vis[i] != 0)
            {
                AC[AC[u].vis[i]].fail = AC[AC[u].fail].vis[i];
                Q.push(AC[u].vis[i]);
            }
            else
                AC[u].vis[i] = AC[AC[u].fail].vis[i];
        }
    }
}
int AC_Query(string s)//AC自动机匹配
{
    int l = s.length();
    int now = 0, ans = 0;
    for (int i = 0; i < l; ++i)
    {
        now = AC[now].vis[s[i] - 'a'];//向下一层
        for (int t = now; t; t = AC[t].fail)//循环求解
            Ans[AC[t].end].num++;
    }
    return ans;
}
int main()
{
    int n;
    while (233)
    {
        cin >> n;
        if (n == 0)break;
        cnt = 0;
        Clean(0);
        for (int i = 1; i <= n; ++i)
        {
            cin >> s[i];
            Ans[i].num = 0;
            Ans[i].pos = i;
            Build(s[i], i);
        }
        AC[0].fail = 0;//结束标志 
        Get_fail();//求出失配指针
        cin >> s[0];//文本串 
        AC_Query(s[0]);
        sort(&Ans[1], &Ans[n + 1]);
        cout << Ans[1].num << endl;
        cout << s[Ans[1].pos] << endl;
        for (int i = 2; i <= n; ++i)
        {
            if (Ans[i].num == Ans[i - 1].num)
                cout << s[Ans[i].pos] << endl;
            else
                break;
        }
    }
    return 0;
}
```

```
//(最终优化版)分别求出每个模式串Ti在S中出现的次数(拓扑优化版)
char s[N], T[N];
int n, cnt, vis[200051], ans, in[N], Map[N];
struct node
{
    int son[26], fail, flag, ans;
    void clear() { memset(son, 0, sizeof(son)), fail = flag = ans = 0; }
}trie[N];
queue<int>q;
void insert(char* s, int num)
{
    int u = 1, 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];
    }
    if (!trie[u].flag)trie[u].flag = num;
    Map[num] = trie[u].flag;
}
void getFail()
{
    for (int i = 0; i < 26; i++)trie[0].son[i] = 1;
    q.push(1);
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        int Fail = trie[u].fail;
        for (int i = 0; i < 26; i++)
        {
            int v = trie[u].son[i];
            if (!v) { trie[u].son[i] = trie[Fail].son[i]; continue; }
            trie[v].fail = trie[Fail].son[i]; in[trie[v].fail]++;
            q.push(v);
        }
    }
}
void topu()
{
    for (int i = 1; i <= cnt; i++)
        if (in[i] == 0)q.push(i);
    while (!q.empty())
    {
        int u = q.front(); q.pop(); vis[trie[u].flag] = trie[u].ans;
        int v = trie[u].fail; in[v]--;
        trie[v].ans += trie[u].ans;
        if (in[v] == 0)q.push(v);
    }
}
void query(char* s)
{
    int u = 1, len = strlen(s);
    for (int i = 0; i < len; i++)
        u = trie[u].son[s[i] - 'a'], trie[u].ans++;
}
int main()
{
    scanf("%d", &n); cnt = 1;
    for (int i = 1; i <= n; i++)
    {
        scanf("%s", s);
        insert(s, i);
    }
    getFail(); scanf("%s", T);
    query(T); topu();
    for (int i = 1; i <= n; i++)printf("%d\n", vis[Map[i]]);
}

自用板子

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值