HDU 2896 病毒侵袭

题意:先给出一个整数n,随后给出n个短字符串,再给出一个整数m,再给出m个长字符串,求出每个长字符串中都有哪几个段字符串。
AC自动机的裸题,可以在root节点上设置一个superroot作为root的fail指针来简化操作,这样对于root,就不用手动把每个子节点入队了·。
因为题目没有说只限于小写字母,所以每个节点应该有128个子节点。

#include <iostream>
#include <algorithm>
#include <string>
#include <stdio.h>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iomanip>
#include <queue>
#define N 45000
using namespace std;
typedef long long ll;
int n,m;
char s1[210],s2[10010];
struct Trier{
    int next[210*500][128],fail[210*500],end[210*500];
    int root,L,super;

    int newNode(){
        L++;
        for(int i=0;i<128;i++){
            next[L][i] = -1;
        }
        end[L] = -1;
        return L; 
    }

    void init(){
        L = -1;
        super = newNode();
        root = newNode();
        for(int i=0;i<128;i++){
            next[super][i] = root;
        }
        fail[root] = super;
    }

    void insert(char s[],int i){
        int t = root;
        for(;*s;s++){
            if(next[t][*s] == -1){
                next[t][*s] = newNode();
            } 
            t = next[t][*s];
        }
        end[t] = i;
    }

    void build(){
        int t = root;
        queue<int>que;
        que.push(root);
        while (!que.empty())
        {
            t = que.front();que.pop();
            for(int i=0;i<128;i++){
                if(next[t][i] != -1){
                    fail[next[t][i]] = next[fail[t]][i];
                    que.push(next[t][i]);
                }else{
                    next[t][i] = next[fail[t]][i];
                }
            }
        }
        
    }
    bool used[510];
    bool query(char s[]){
        bool ans = 0;
        memset(used,0,sizeof(used));
        int t = root;
        for(;*s;s++){
            t = next[t][*s];
            for(int u = t;u != root;u = fail[u]){
                if(end[u] != -1){
                    used[end[u]] = 1;
                    ans = 1;
                }
            }
        }
        return ans;
    }
};
Trier aa;


int main(){
    int i,j,x,y;
    aa.init();
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        scanf("%s",s1);
        aa.insert(s1,i);
    }
    aa.build();
    scanf("%d",&m);

    int total = 0;

    for(i=1;i<=m;i++){
        scanf("%s",s2);
        if(aa.query(s2)){
            total++;
            printf("web %d:",i);
            for(j=0;j<=n;j++){
                if(aa.used[j]){
                    printf(" %d",j);
                }
            }
            printf("\n");
        }
    }
    printf("total: %d\n",total);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值