现在的位置: 首页 > 综合 > 正文

hdu 2896 病毒侵袭 (字符串_AC自动机)

2013年10月11日 ⁄ 综合 ⁄ 共 1719字 ⁄ 字号 评论关闭

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2896

题目大意:给定n个病毒代码和m个网站源码,问每个网站源码包含哪些病毒。

解题思路:用n个病毒代码构造一棵trie树,再增加fail指针。最后只要进行查询就可以了,差不多就是模板题。最后将求得的病毒序号排序输出即可。

测试数据:

aaa
bbb
ccc
3
aaabcccbb
aaabbbccc

bbaacc


代码:

#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;


struct node {

    int flag,rec;
    node *next[100],*fail;
    node () {
    
        flag = rec = 0;
        memset(next,NULL,sizeof(next));
        fail = NULL;
    }
}*q[1000010];
int  n,m,cnt,tot,cas;
int  head,tail,arr[501];
char key[201],str[100010];


void Insert(node *root,char *str,int loc) {

    int i = 0,k;
    node *p = root;

    while (str[i]) {

        k = str[i++] - 31;
        if (p->next[k] == NULL)
            p->next[k] = new node();
        p = p->next[k];
    }


    p->flag = 1;
    p->rec = loc;
}
void my_accept(node *root) {
//构造失败指针
    root->fail = NULL;
    q[head++] = root;


    while (head != tail) {

        node *temp = q[tail++];                                //获取头结点
        node *p = NULL;
        for (int i = 0; i < 100; ++i) {
        //遍历每个子节点
            if (temp->next[i] != NULL) {
            //子节点存在的情况
                if (temp == root) temp->next[i]->fail = root;//失败节点指向头结点
                else {
                //回溯
                    p = temp->fail;
                    while (p != NULL) {

                        if (p->next[i] != NULL) {
                        //找到匹配数
                            temp->next[i]->fail = p->next[i];
                            break;
                        }
                        p = p->fail;
                    }
                    if (p == NULL) temp->next[i]->fail = root;
                }//else
                q[head++] = temp->next[i];
            }//if ( != NULL
        }//for i
    }//while head != tail
}
void Search(node *root,char *str) {

    int i = 0,k;
    node *p = root,*temp;


    while (str[i]) {

        k = str[i++] - 31;
        while (p->next[k] == NULL && p != root)
            p = p->fail;                                //往前回溯求最长后缀
        p = (p->next[k] ? p->next[k] : root);
        temp = p;


        while (temp != root) {

            if (temp->flag == 1)
                arr[cnt++] = temp->rec;
            temp = temp->fail;
        }
    }
}


int main()
{
    int i,j,k;


    while (scanf("%d",&n) != EOF) {

        node *root = new node();
        for (i = 1; i <= n; ++i)
            scanf("%s",key),Insert(root,key,i);


        tot = head = tail = 0;
        my_accept(root);


        scanf("%d",&m);
        for (i = 1; i <= m; ++i) {

            scanf("%s",str);
            cnt = 0;
            Search(root,str);
            if (cnt == 0) continue;


            tot++;
            printf("web %d:",i);
            sort(arr,arr+cnt);
            for (j = 0; j < cnt; ++j)
                printf(" %d",arr[j]);
            printf("\n");
        }
        printf("total: %d\n",tot);
    }
}

本文ZeroClock原创,但可以转载,因为我们是兄弟。

抱歉!评论已关闭.