[hdu-2896]病毒侵袭 题解

本文详细解析了一道关于AC自动机的编程题,通过构建AC自动机并实现字符串匹配算法来找出模式串在匹配串中的出现情况。文章提供了完整的代码实现及注释,帮助读者理解AC自动机的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目传送门
题意解析:似乎题目是中文的,所以就大概说一下,给你n个模式串,和m个匹配串,让你找出分别是哪几个模式串出现了,题目中保证了匹配串中最多出现3个模式串,并且最后让你输出可以匹配的个数。


AC自动机的裸题,在危险节点上记录编号就好了。
代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=a;i>=n;i--)
#define Clear(a,x) memset(a,x,sizeof(a))
#define ll long long
#define INF 2000000000
#define eps 1e-8
using namespace std;
int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9') f=ch=='-'?-1:f,ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxnode=100005,maxsize=128;
char s[10005];
int n,m,ans;
struct AC{
    int ch[maxnode][maxsize],val[maxnode],f[maxnode];
    int cnt;
    inline void init(){
        cnt=0;
        Clear(ch[0],0);
        val[0]=f[0]=0;
    }   
    inline void insert(char *s,int v){
        int len=strlen(s),u=0;
        rep(i,0,len-1){
            int id=s[i];
            if (!ch[u][id]){
                ch[u][id]=++cnt;
                Clear(ch[cnt],0);
                val[cnt]=0;
            }
            u=ch[u][id];
        }
        val[u]=v;
    }
    inline void getfail(){
        queue<int> q;
        f[0]=0;
        rep(i,0,maxsize-1){
            int u=ch[0][i];
            if (u){
                f[u]=0;
                q.push(u);
            }
        }
        while (!q.empty()){
            int r=q.front();
            q.pop();
            rep(i,0,maxsize-1){
                int u=ch[r][i];
                if (!u) ch[r][i]=ch[f[r]][i];
                    else{
                        f[u]=ch[f[r]][i];
                        q.push(u);
                    }
            }
        }
    }
    int a[505];
    inline void find(char *s,int v){
        int len=strlen(s),u=0;
        int tot=0;
        bool flag=0;
        rep(i,0,len-1){
            int id=s[i];
            u=ch[u][id];
            int tmp=u;
            while (tmp!=0){
                if (val[tmp]){
                    a[++tot]=val[tmp];
                    flag=1;
                }
                tmp=f[tmp];
            }
        }
        if (!flag) return;
        ans++;
        printf("web %d: ",v);
        sort(a+1,a+tot+1);
        rep(i,1,tot-1) printf("%d ",a[i]);
        printf("%d\n",a[tot]);
    }
}ac;
int main(){
    while (~scanf("%d",&n)){
        ac.init();
        rep(i,1,n){
            scanf("%s",s);
            ac.insert(s,i);
        }
        ac.getfail();
        ans=0;
        m=read();
        rep(i,1,m){
            scanf("%s",s);
            ac.find(s,i);
        }
        printf("total: %d\n",ans);
    }
    return 0;
}

总感觉用结构体比较漂亮。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值