HDU 2896 AC自动机

中文题,题意就不解释了。

这道题把我坑了下,应该是做题不仔细的原因,一开始我以为是26个字母的(没认真读题,看样例的结果) ,然后RE了好几发,最多发现题目里的描述是ASCLL码表里面的可见字符,然后将建字典树过程中的0 - 25的循环改成0 - 127 就过了。

讲一下思路,这道题就是AC自动机的模版题,唯一需要注意的就是加一个id的域来存这个字符串的序号,最后输出的时候要按从小到大的顺序,我直接全部扔进set输出了。

不过我感觉数据有点水啊。。。总感觉A的不是很踏实。

加了释放内存,但是发现内存没比原来的少,难道数据只有一组o(︶︿︶)o 

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <stack>
#include <map>
#include <iomanip>
#define PI acos(-1.0)
#define Max 2505
#define inf 1<<28
#define LL(x) ( x << 1 )
#define RR(x) ( x << 1 | 1 )
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
#define PII pair<int,int>
using namespace std;


struct node {
    node *fail ;
    node *next[128] ;
    int count ;
    int id ;
    node() {
        fail = 0 ;
        count = 0 ;
        mem(next , 0) ;
        id = 0 ;
    }
}*qe[1000005] ;
node *root = 0 ;
//insert a[] .
void insert(char *a,int id) {
    node *p = root ;
    int l = strlen(a) ;
    for (int i = 0 ; i < l ; i ++ ) {
        int tt = a[i] ;
        if(p -> next[tt] == 0) {
            p -> next[tt] = new node() ;
        }
        p = p -> next[tt] ;
    }
    p -> count ++ ;
    p -> id = id ;
}
//build *fail .
void build() {
    root -> fail = 0 ;
    int h = 0 , t = 0 ;
    qe[h ++ ] = root ;
    while(h > t) {
        node *temp = qe[t ++ ] ;
        node *p = 0 ;
        for (int i = 0 ; i < 128 ; i ++ ) {
            if(temp -> next[i] != 0) {
                if(temp == root)temp -> next[i] -> fail = root ;
                else {
                    p = temp -> fail ;
                    while(p != 0) {
                        if(p -> next[i] != 0) {
                            temp -> next[i] -> fail = p -> next[i] ;//找到匹配
                            break ;
                        }
                        p = p -> fail ;
                    }
                    if(p == 0)temp -> next[i] -> fail = root ;//如果没找到,则将fail指向root
                }
                qe[h ++ ] = temp -> next[i] ;
            }
        }
    }
}
set<int>anss[1111] ;
int search(char *a ,int id) {
    int l = strlen(a) ;
    node *p = root ;
    int ans = 0 ;
    for (int i = 0  ; i < l ; i ++ ) {
        int tt = a[i] ;
        while(p -> next[tt] == 0 && p != root)p = p -> fail ;
        p = p -> next[tt] ;
        p = (p == 0) ? root : p ;
        node *temp = p ;
        while(temp != root && temp -> count != 0) {
            ans += temp -> count ;
            anss[id].insert(temp -> id) ;
            //temp -> count = -1 ;
            temp = temp -> fail ;
        }
    }
    return ans ;
}

void deleteAll(node *p){
    for (int i = 0 ; i < 128 ; i ++ )
    if(p -> next[i] != 0){
        deleteAll(p -> next[i]) ;
    }
    delete p ;
}
char a[11111] ;
int num[1111] ;
int main() {
    int n ;
    cin >> n ;
    getchar() ;
    root = new node() ;
    for (int i = 1 ; i <= n ;i ++ ){
        gets(a) ;
        insert(a ,i ) ;
    }
    int m ;
    cin >> m ;
    getchar() ;
    build() ;
    for (int i = 1 ; i <= m ;i ++ ){
        gets(a) ;
        num[i] = search(a , i) ;
    }
    int cc = 0 ;
    for (int i = 1 ; i <= m ;i ++ ){
        if(num[i]){
            printf("web %d:",i) ;
            for(set<int>::iterator p = anss[i].begin() ; p != anss[i].end() ; ++ p)
            cout <<" "<< *p ;
            cc ++ ;
            puts("") ;
        }
    }
    printf("total: %d\n",cc) ;
    deleteAll(root) ;
    return 0 ;
}

贴一个AC自动机静态的模版

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include <set>
using namespace std;
char ss[1000010];
int n,cnt,ans;
struct node {
    int num;
    int next[128];
    int fail;
    int id ;
    void init() {
        memset(next,-1,sizeof(next));
        fail=-1;
        num=0;
        id = 0 ;
    }
} a[500000];
void insert(char s[],int id) {
    int p=0,i=0;
    int len=strlen(s);
    while(i<len) {
        int k=s[i] ;
        if(a[p].next[k]==-1) {
            a[cnt].init();
            a[p].next[k]=cnt++;
        }
        i++;
        p=a[p].next[k];
    }
    a[p].num++;
    a[p].id = id ;
}
queue<int>q;
void ac_bfs() {
    q.push(0);
    while(!q.empty()) {
        int p=q.front();
        q.pop();
        int fail=0;
        for(int i=0; i<128; i++)if(a[p].next[i]!=-1) {
                if(p==0) {
                    a[a[p].next[i]].fail=p;
                } else {
                    fail=a[p].fail;
                    while(fail!=-1) {
                        if(a[fail].next[i]!=-1) {
                            a[a[p].next[i]].fail=a[fail].next[i];
                            break;
                        }
                        fail=a[fail].fail;
                    }
                    if(fail==-1)a[a[p].next[i]].fail=0;
                }
                q.push(a[p].next[i]);
            }
    }
}
set<int>fk[1111] ;
int query(char s[] ,int id) {
    int i=0,len=strlen(s);
    int p=0,ans=0;
    while(i<len) {
        int k=s[i] ;
        while(a[p].next[k]==-1&&p!=0)p=a[p].fail;
        p=a[p].next[k];
        p=(p==-1)?0:p;
        int tmp=p;
        while(tmp!=0 && a[tmp].num != 0) {
            ans+=a[tmp].num;
            fk[id].insert(a[tmp].id) ;
            tmp=a[tmp].fail;
        }
        i++;
    }
    return ans;
}


char virus[11111] ;
int fkk[1111] ;
int main() {
    int n ;
    cin >> n ;
    cnt = 1 ;
    a[0].init() ;
    getchar() ;
    for (int i = 1 ; i <= n ; i ++ ) {
        gets(virus) ;
        insert(virus,i) ;
    }
    int m ;
    cin >> m ;
    ac_bfs() ;
    getchar() ;
    int cc = 0 ;
    for (int i = 1 ; i <= m ; i ++ ) {
        gets(virus) ;
        fkk[i] = query(virus , i) ;
    }
    for (int i = 1 ; i <= m ; i ++ ) {
        if(fkk[i]) {
            printf("web %d:",i) ;
            for(set<int>::iterator p = fk[i].begin() ; p != fk[i].end() ; ++ p)
                cout <<" "<< *p ;
            cc ++ ;
            puts("") ;
        }
    }
    printf("total: %d\n",cc) ;
    return 0 ;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值