zoukankan      html  css  js  c++  java
  • HDU 3065 病毒侵袭持续中 (AC自动机)

    题目链接

    Problem 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

    分析:
    给你n个子串,然后从一个字符串中查找这些子串哪些出现过,出现了多少次。

    代码:

    #include<stdio.h>
    #include<iostream>
    #include<queue>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    struct Node
    {
        Node *next[26];//病毒只涉及到26个英文字母
        Node *fail;//fail指针
        int id;//病毒的编号
        Node()//节点初始化
        {
            for(int i=0; i<26; i++)
                next[i]=NULL;
            fail=NULL;
            id=0;
        }
    } *tree[500009];
    
    Node *root;
    int cnt[1009];//每个病毒的出现次数
    int head,tail;
    char vir[1009][55];//存放病毒的信息
    char source[2000009],s[2000009];
    
    void Insert(char *str,int index)//插入信息
    {
        Node *p=root;
        int i=0,pos;
        while(str[i])
        {
            pos=str[i]-'A';//字母转数字
            if(p->next[pos]==NULL)//如果当前的节点不存在,则建立新的节点
                p->next[pos]=new Node();
            p=p->next[pos];//指针接着往下指
            i++;
        }
        p->id=index;//记录这个病毒的编号
    }
    void build_ac_automation(Node *root)//寻找fail指针
    {
        root->fail=NULL;
        tree[tail++] = root;
        Node *p=NULL;
        while(head<tail)//相当于是一个广搜的过程
        {
            Node * temp=tree[head++];
            for(int i=0; i<26; i++)
            {
                if(temp->next[i]!=NULL)//存在当前的节点
                {
                    if(temp==root)//如果这个节点是根节点的话
                        temp->next[i]->fail=root;//那么他的孩子的fail指针就都是根节点
                    else
                    {
                        p=temp->fail;//指向当前的根节点
                        while(p!=NULL)
                        {
                            if(p->next[i]!=NULL)//当前结点下存在相同的节点
                            {
                                temp->next[i]->fail=p->next[i];//那么就寻找到了fail指针
                                break;
                            }
                            p=p->fail;
                        }
                        if(p==NULL) temp->next[i]->fail=root;//没有找到,则fail指针指向根节点
                    }
                    tree[tail++]=temp->next[i];
                }
            }
        }
    }
    
    void query(char *str)
    {
        int i=0,index;
        Node *p=root;
        while(str[i])
        {
            index=str[i]-'A';//字母转数字
            while(p->next[index]==NULL&&p!=root)//不是根节点,则一直寻找到fail指针
                p=p->fail;
            p=p->next[index];
            if(p==NULL) p=root;
            Node *temp=p;
            while(temp!=root&&temp->id>0)//存在这个病毒
            {
                cnt[temp->id]++;//病毒数+
                temp=temp->fail;
            }
            i++;
        }
    }
    int main()
    {
        int n;
        while(~scanf("%d",&n))
        {
            memset(cnt,0,sizeof(cnt));
            head=tail=0;
            root=new Node();
            getchar();
            for(int i=1; i<=n; i++)
            {
                scanf("%s",vir[i]);
                Insert(vir[i],i);
            }
            build_ac_automation(root);
            scanf("%s",source);
            int len=strlen(source);
            int l=0;
            for(int i=0; i<=len; i++)
            {
                if(source[i]>='A'&&source[i]<='Z')
                {
                    s[l++]=source[i];
                }
                else
                {
                    s[l]='';
                    query(s);
                    l=0;
                }
            }
            for(int i = 1; i <= n; i++)
            {
                if(cnt[i])
                    printf("%s: %d
    ",vir[i], cnt[i]);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Go-常量-const
    centos-安装python3.6环境并配置虚拟环境
    centos-环境变量配置
    linux_命令格式和命令提示符
    linux_基础调优
    使用 Docker 容器应该避免的 10 个事情
    Linux--多网卡的7种Bond模式和交换机配置
    《Linux内核精髓:精通Linux内核必会的75个绝技》目录
    《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #21FUSE
    《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #20 使用fio进行I/O的基准测试
  • 原文地址:https://www.cnblogs.com/cmmdc/p/7898553.html
Copyright © 2011-2022 走看看