AC自动机,知识点+hdu模板题

hdu2896

hdu3065


对于AC自动机的理解,转载注明出自bestsort.cn  说得贼棒,图文并茂


自己的模板

 1 int trie[maxn][27];
 2 int cntword[maxn];
 3 int fail[maxn];
 4 int cnt=1;
 5 void add(char *s){
 6     it root = 0,l=strlen(s);
 7     for(it i=0;i<l;i++){
 8         int next =s[i]-'A';
 9         if(!trie[root][next])
10             trie[root][next] = cnt++;
11         root = trie[root][next];
12     }
13     cntword[root]++;//这里没有重复
14 }
15 void getFail(){
16     queue <int>q;
17     for(it i=0;i<26;i++){
18         if(trie[0][i]){
19             fail[trie[0][i]] = 0;
20             q.push(trie[0][i]);
21         }
22     }
23     while(!q.empty()){
24         int now = q.front();
25         q.pop();
26         for(int i=0;i<26;i++){
27             if(trie[now][i]){
28                 fail[trie[now][i]] = trie[fail[now]][i];
29                 q.push(trie[now][i]);
30             }
31             else
32                 trie[now][i] = trie[fail[now]][i];
33         }
34     }
35 }
36 int query(char *s){
37     int now = 0,ans = 0,l=strlen(s);
38     for(it i=0;i<l;i++){
39         if(s[i]<'A' ||s[i]>'Z'){now=0;continue;}//如果字符串有不是A~Z的now归零
40         now = trie[now][s[i]-'A'];
41         for(it j=now;j && cntword[j]!=-1;j=fail[j]){
42             cntword[j]=-143             ans++;//出现过的字符串,标记
44         }
45     }
46     return ans;
47 }

 

 

hdu2896 病毒侵袭(模板题)

题意:

输入n个字符串(n<=500),这n个字符串是指病毒,字符串长度不超过200,字符是ASCII码可见字符.

给m个字符串(长度不超过1e5)表示网址(m<=1000),说这个网址会有多少病毒,最后统计有多少带病毒的网址

样例输入                                                      样例输出

3                                                                   web 1: 1 2 3
aaa                                                               total: 1             
bbb
ccc
2
aaabbbccc
bbaacc

 思路:

因为字符是ASCII码可见字符,所以字符范围128,tire长度[200*500][128],用cntword标记病毒序号。

这题hduG++,mle到自闭,然后换了C++就过了,毒毒毒毒瘤。

#include<iostream>
#include<map>
#include<set>
#include<queue>
#include<stdio.h>
#include<string.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define il inline
#define it register int
#define inf 0x3f3f3f3f
#define lowbit(x) (x)&(-x)
#define pii pair<int,int>
#define mak(n,m) make_pair(n,m)
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 998244353
const int maxn=1e5+10;
int trie[maxn][128];
int cntword[maxn];
int fail[maxn];
int cnt=0,tot=0,num=1;
map<char,int>mp;
void add(char *s,int num1){
    it root = 0,l=strlen(s);
    for(it i=0;i<l;i++){
        int next =mp[s[i]];
        if(next==0){next=num;
            mp[s[i]]=num++;
        }
        if(!trie[root][next])
            trie[root][next] = ++cnt;
        root = trie[root][next];
    }
    cntword[root]=num1;
}
void getFail(){
    queue <int>q;
    for(it i=1;i<=num;i++){
        if(trie[0][i]){
            fail[trie[0][i]] = 0;
            q.push(trie[0][i]);
        }
    }
    while(!q.empty()){
        int now = q.front();
        q.pop();
        for(int i=1;i<=num;i++){
            if(trie[now][i]){
                fail[trie[now][i]] = trie[fail[now]][i];
                q.push(trie[now][i]);
            }
            else
                trie[now][i] = trie[fail[now]][i];
        }
    }
}
void query(char *s,int num1){
    int now = 0,ans = 0,l=strlen(s);
    set<int>st;
    for(it i=0;i<l;i++){
        now = trie[now][mp[s[i]]];
        for(it j=now;j && cntword[j]!=-1;j=fail[j]){
            st.insert(cntword[j]);
            //cntword[j] = -1;
        }
    }
    if(st.size()){tot++;
        printf("web %d:",num1);
        for(auto &i:st){
            printf(" %d",i);
        }
        printf("\n");
    }
}
char s[10010],ss[210];
int main(){
    int n,m;mem(cntword,-1);
    scanf("%d",&n);
    for(it i=1;i<=n;i++){
        scanf("%s",ss);
        add(ss,i);
    }
    getFail();
    scanf("%d",&m);
    for(it i=1;i<=m;i++){
        scanf("%s",s);
        query(s,i);
    }
    printf("total: %d\n",tot);
    return 0;
}

 

 

 

 

hdu3065 病毒侵袭持续中(模板题)

题意:

给n个A~Z字符串,字符串长度不超过50(n<=1000),再给一个字符串长度2000000的,里面的字符是ASCII码可见字符,问n出现过几次

样例输入                                                    样例输出

3                                                                AA: 2

AA                                                             CC: 1

BB

CC

ooxxCC%dAAAoen....END

思路:

模板套一套,但问题是tire[50*1000][26]是re…,要[1e5][26]

 

#include<iostream>
#include<map>
#include<set>
#include<queue>
#include<stdio.h>
#include<string.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define il inline
#define it register int
#define inf 0x3f3f3f3f
#define lowbit(x) (x)&(-x)
#define pii pair<int,int>
#define mak(n,m) make_pair(n,m)
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 998244353
const int maxn=1e5+10;
int trie[maxn][27];
int cntword[maxn];
int fail[maxn];
int cnt=0,tot=0,n;
void add(char *s,int num1){
    it root = 0,l=strlen(s);
    for(it i=0;i<l;i++){
        int next =s[i]-'A';
        if(!trie[root][next])
            trie[root][next] = ++cnt;
        root = trie[root][next];
    }
    cntword[root]=num1;
}
void getFail(){
    queue <int>q;
    for(it i=0;i<26;i++){
        if(trie[0][i]){
            fail[trie[0][i]] = 0;
            q.push(trie[0][i]);
        }
    }
    while(!q.empty()){
        int now = q.front();
        q.pop();
        for(int i=0;i<26;i++){
            if(trie[now][i]){
                fail[trie[now][i]] = trie[fail[now]][i];
                q.push(trie[now][i]);
            }
            else
                trie[now][i] = trie[fail[now]][i];
        }
    }
}
char s1[2000010],ss[1010][55];
void query(char *s){
    int now = 0,ans = 0,l=strlen(s);
    int numm[1010]={0};
    for(it i=0;i<l;i++){
        if(s[i]<'A' ||s[i]>'Z'){now=0;continue;}
        now = trie[now][s[i]-'A'];
        for(it j=now;j && cntword[j]!=-1;j=fail[j]){
            numm[cntword[j]]++;
           //cout<<cntword[j]<<endl;
        }
    }
    for(it i=1;i<=n;i++){
        if(numm[i]==0){continue;}
        printf("%s: %d\n",ss[i],numm[i]);
    }
}

int main(){
    while(~scanf("%d",&n)){
    mem(cntword,-1);mem(trie,0);
    for(it i=1;i<=n;i++){
        scanf("%s",ss[i]);
        add(ss[i],i);
    }
    getFail();
    scanf("%s",s1);
    query(s1);
    }
    return 0;
}

 

 

对了对了还有一个hdu2222,我用tire树莽过的题

这里就贴一个代码吧

 

#include<queue>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
#include<string>
#include<vector>
#include<functional>
#pragma warning(disable:4996)
using namespace std;
const int maxn = 1000010;
#define inf 0x3f3f3f3f
#define mem(k,b) memset(k,b,sizeof(k))
#define ll long long
char s[maxn];
char ss[55];
int k = 1, t, n;
int g[240000][26] = { 0 }, vis[240000] = { 0 };
inline void insert(char *w){
    int p = 0, l = strlen(w);
    for (int i = 0; i < l; i++){
        int c = w[i] - 'a';
        if (!g[p][c]){
            g[p][c] = k++;
        }
        p = g[p][c];
    }
    vis[p]++;
    return;
}
inline int search(char *w){
    int l = strlen(w);
    int sum = 0;
    for (int j = 0; j < l; j++){
        int p = 0;
        for (int i = j; i < j + 50; i++){
            if (i == l){
                break;
            }
            int c = w[i] - 'a';
            if (!g[p][c]){
                break;
            }
            p = g[p][c];
            if (vis[p]){
                sum += vis[p];
                vis[p] = 0;
            }
        }
    }
    return sum;
}
int main()
{
    scanf("%d", &t);
    while (t--){
        k = 1; mem(vis, 0); mem(g, 0);
        scanf("%d", &n);
        getchar();
        for (int i = 0; i < n; i++){
            gets(ss);
            insert(ss);
        }
        gets(s);
        printf("%d\n", search(s));

    }
    return 0;
}

 

posted @ 2020-03-12 14:51  ouluy  阅读(122)  评论(0编辑  收藏  举报