• AC自动机---病毒侵袭持续中


    HDU 3065

    题目网址: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=110773#problem/C

    Description

    小t非常感谢大家帮忙解决了他的上一个问题。然而病毒侵袭持续中。在小t的不懈努力下,他发现了网路中的“万恶之源”。这是一个庞大的病毒网站,他有着好多好多的病毒,但是这个网站包含的病毒很奇怪,这些病毒的特征码很短,而且只包含“英文大写字符”。当然小t好想好想为民除害,但是小t从来不打没有准备的战争。知己知彼,百战不殆,小t首先要做的是知道这个病毒网站特征:包含多少不同的病毒,每种病毒出现了多少次。大家能再帮帮他吗?
     

    Input

    第一行,一个整数N(1<=N<=1000),表示病毒特征码的个数。 
    接下来N行,每行表示一个病毒特征码,特征码字符串长度在1―50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。 
    在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。 
     

    Output

    按以下格式每行一个,输出每个病毒出现次数。未出现的病毒不需要输出。 
    病毒特征码: 出现次数 
    冒号后有一个空格,按病毒特征码的输入顺序进行输出。 
     

    Sample Input

    3 AA BB CC ooxxCC%dAAAoen....END
     

    Sample Output

    AA: 2 CC: 1

    Hint

     Hit: 题目描述中没有被提及的所有情况都应该进行考虑。比如两个病毒特征码可能有相互包含或者有重叠的特征码段。 计数策略也可一定程度上从Sample中推测。 

    思路: 这题要注意多组输入,上一题不用多组输入就过了,这题居然必须多组输入…… 还有要注意每个测试样例结束后要要将结构体空间清理掉,否则会超内存。 解题过程,在AC自动机模板上在结构体中加一个标记,用来标记模式串(病毒的特征码)的序号。在计数过程中,不用把模式串标记为-1,因为要重复计数。

    代码如下:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define N 50010
    char str[2000010],keyword[1005][55];
    int head,tail;
    int C[1005];
    
    struct node
    {
        node *fail;
        node *next[95];
        int b;
        int count;
        node()
        {
            fail=NULL;
            b=0;
            count=-1;
            for(int i=0; i<95; i++)
                next[i]=NULL;
        }
    }*q[N];
    node *root;
    
    void insert(char *str,int x) ///建立Trie
    {
        int temp,len;
        node *p=root;
        len=strlen(str);
        for(int i=0; i<len; i++)
        {
            temp=str[i]-32;
            if(p->next[temp]==NULL)
                p->next[temp]=new node();
            p=p->next[temp];
        }
        p->count++;
        p->b=x;///在该串结束字符位置标记该串的序号;
    }
    
    void setfail() ///使用bfs初始化fail指针;
    {
        q[tail++]=root;
        while(head!=tail)
        {
            node *p=q[head++];
            node *temp=NULL;
            for(int i=0; i<95; i++)
                if(p->next[i]!=NULL)
                {
                    if(p==root) ///首字母的fail必指向根
                        p->next[i]->fail=root;
                    else
                    {
                        temp=p->fail; ///失败指针
                        while(temp!=NULL) ///2种情况结束:匹配为空or找到匹配
                        {
                            if(temp->next[i]!=NULL) ///找到匹配
                            {
                                p->next[i]->fail=temp->next[i];
                                break;
                            }
                            temp=temp->fail;
                        }
                        if(temp==NULL) ///为空则从头匹配
                            p->next[i]->fail=root;
                    }
                    q[tail++]=p->next[i]; ///入队(p->next[i]的fail指针已设置m完);
                }
        }
    }
    
    void query()
    {
        int index,len;
        node *p=root;
        len=strlen(str);
        for(int i=0; i<len; i++)
        {
            index=str[i]-32;
            while(p->next[index]==NULL&&p!=root) p=p->fail;///跳转失败指针
            p=p->next[index];
            if(p==NULL)
                p=root;
            node *temp=p; ///p不动,temp计算后缀串
            while(temp!=root&&temp->count!=-1)
            {
                C[temp->b]++;
                temp=temp->fail;
            }
        }
        return ;
    }
    
    void free_(node *r)
    {
        for(int i=0;i<95;i++)
        {
            if(r->next[i])
            free_(r->next[i]);
        }
        free(r);
    }
    
    int main()
    {
        int n;
        while(scanf("%d",&n)!=EOF)
        {
            memset(C,0,sizeof(C));
            getchar();
            head=tail=0;
            root=new node();
            for(int i=1; i<=n; i++)
            {
                gets(keyword[i]);
                insert(keyword[i],i);
            }
            setfail();
            gets(str);
            query();
            for(int i=1; i<=n; i++)
            if(C[i]) printf("%s: %d
    ",keyword[i],C[i]);
            free_(root);///释放开辟的结构体空间;
        }
        return 0;
    }
  • 相关阅读:
    hdoj1587
    欧拉定理及其应用
    hdoj1571
    hdoj1050
    POJ推荐50题
    poj2593
    hdoj1286
    hdoj1215七夕节
    我的Linux软件
    ACM题目推荐--《算法艺术与信息学竞赛》(转)
  • 原文地址:https://www.cnblogs.com/chen9510/p/5334803.html
Copyright © 2020-2023  润新知