自动AC机是如何运行的

在这里插入图片描述

今 天 你 今天你 AC 了 吗 , 快 来 康 康 了吗,快来康康 自 动 自动 AC 机 机 来 解 决 你 每 天 的 烦 恼 吧 来解决你每天的烦恼吧 ~

绿 掉 绿掉 绿 的 代 码 的代码

敲 简 单 的 , 康 康 代 码 吧 ! 敲简单的,康康代码吧!

#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct Trie_Tree{
    ll fail;
    ll child[27];//每父节点下的子节点有26个(26个字母)※child[]表示当前访问的节点 
    ll end;//标记有几个单词以这个节点结尾
}ac[1000000 + 10];
ll cnt = 0;//Trie的指针
inline void Build(string mushichuan){//建树 
    ll l = mushichuan.length();
    ll now = 0;//访问字典树的当前位置 
    for(ll i = 0; i < l; i++){//构造Trie树
        if(ac[now].child[mushichuan[i] - 'a'] == 0)//树没这个节点, s[i] - 'a' 把对应的字母变成数字 
            ac[now].child[mushichuan[i] - 'a'] = ++cnt;//如 "A B C" 需要构造三层,每一层都事先把 a~z 26个字母打好 
            now = ac[now].child[mushichuan[i] - 'a'];//往下递归
    }//最后跳出循环需把单词结尾标记一下 
    ac[now].end++;
}
void get_fail(){//构造fail指针
    queue <ll> q;
    for(ll i = 0; i <= 26; i++){//初始条件 
        if(ac[0].child[i] != 0){//构造了此节点, ac[0] 表示根节点 
            ac[ac[0].child[i]].fail = 0;//先把所有的第二层节点都指向根节点
            q.push(ac[0].child[i]);//把根节点的子节点 push 进 queue 中     
        }
    }
    while(!q.empty()){//bfs求每一相同的字符串,再将fail指针指向相同字符串的子节点 
        ll father = q.front();
        q.pop();
        for(ll i = 0; i < 26; i++){
            if(ac[father].child[i] != 0){//父节点下存在子节点
                ac[ac[father].child[i]].fail = ac[ac[father].fail].child[i];//看图解
                q.push(ac[father].child[i]);//像第一层把父节点的子节点 push 进 queue 中
            }
            else//父节点下不存在子节点
                ac[father].child[i] = ac[ac[father].fail].child[i];//虚根(看图解) 
        }
    }
}
ll AC_COUT(string wenbenchuan){//自动AC机的匹配
    ll l = wenbenchuan.length();
    ll now = 0, ans = 0;//now = 0 先从根结点出发 
    for(ll i = 0; i< l; i++){
        now = ac[now].child[wenbenchuan[i] - 'a'];//向下走, s[i] - 'a' 把对应的字母变成数字 
        for(ll next = now; next && ac[next].end != -1; next = ac[next].fail){//下一个节点没有 || 没有访问过, 循环求解
            ans += ac[next].end;//计算单词节点(看图解) 
            ac[next].end = -1;//与上方对应,就不会重复使用 
        }
    }
    return ans; 
}
int main(){
    ll n;
    string mushichuan, wenbenchuan;
    cin >> n;
    for(ll i = 1; i <= n; i++){
        cin >> mushichuan;
        Build(mushichuan);//建树
    }
    ac[0].fail = 0;//根节点的 fail 指针指向 0(结束标志)
    get_fail();//构造fail指针
    cin >> wenbenchuan;
    cout << AC_COUT(wenbenchuan) << endl;
    return 0;
}

希 望 大 家 多 多 提 出 宝 贵 的 意 见 ! 希望大家多多提出宝贵的意见!

既 然 你 耐 心 看 完 了 这 篇 题 解 , 何 不 如 既然你耐心看完了这篇题解,何不如 一键三连 再 走 呢 ? T h a n k s ♪ ( ・ ω ・ ) ノ ( 再走呢?Thanks♪(・ω・)ノ( Thanks(ω)(B 站 看 多 了 [ 复 杂 ] ) 站看多了[复杂]) [])

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值