【字符串】hdu5880 ac自动机模板

 

ac自动机:

给你若干个单词,判断一段文字里边这些单词出现了吗,在哪出现,出现几次?

 

首先是字典树模板:

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
const int maxn=1e3+50;
struct trie_node{
    int count;
    trie_node*son[26];
};
trie_node* new_node()
{
    trie_node* pnode=new trie_node();
    pnode->count=0;
    for(int i=0;i<26;i++)pnode->son[i]=NULL;
    return pnode;
}
void trie_insert(trie_node *root,char key[])
{
    trie_node* node=root;
    char *p=key;
    while(*p)
    {
        if(node->son[*p-'a']==NULL)node->son[*p-'a']=new_node();
        node=node->son[*p-'a'];
        ++p;
    }
    node->count+=1;
}
int trie_search(trie_node *root,char key[])
{
    trie_node*node=root;
    char *p=key;
    while(*p&&node!=NULL)
    {
        node=node->son[*p-'a'];
        ++p;
    }
    if(node==NULL)return 0;
    else return node->count;
}

int main()
{
    int n,q,i,j;
    char s[20];
    trie_node *root;
    root=new_node();
    scanf("%d%d",&n,&q);
    while(n--)
    {
        scanf("%s",s);
        trie_insert(root,s);
    }
    while(q--)
    {
        scanf("%s",s);
        printf("%d\n",trie_search(root,s));
    }
}
View Code

时隔几个月,觉得上面那个模板好丑,搬了oiwiki的板子:

struct trie {
  int nex[100000][26], cnt;
  bool exist[100000];  // 该结点结尾的字符串是否存在

  void insert(char *s, int l) {  // 插入字符串
    int p = 0;
    for (int i = 0; i < l; i++) {
      int c = s[i] - 'a';
      if (!nex[p][c]) nex[p][c] = ++cnt;  // 如果没有,就添加结点
      p = nex[p][c];
    }
    exist[p] = 1;
  }
  bool find(char *s, int l) {  // 查找字符串
    int p = 0;
    for (int i = 0; i < l; i++) {
      int c = s[i] - 'a';
      if (!nex[p][c]) return 0;
      p = nex[p][c];
    }
    return exist[p];
  }
};
View Code

 

 

然后是ac自动机:字典树+fail指针 重点在getfail函数

例题是 hdu5880

一整天,一直被卡MLE,改成指针形式的动态开点也卡。

然后去搜,终于搜到一篇博客。

博客说:不要一次性memset,而是,用到一个点,memset一次。 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define debug printf("!");
using namespace std;
const int maxn=1e6+5;
struct T{
    int fail;
    int vis[26];
    int dep;
}ac[maxn];

int cnt;

char s[maxn];

void init(int t)
{
    ac[t].fail=ac[t].dep=0;
    memset(ac[t].vis,0,sizeof(ac[t].vis));
}


inline void insert(char *s)
{
    int len=strlen(s),i,p=0,dep=0;
    for(i=0;i<len;i++)
    {
        dep++;
        if(!ac[p].vis[s[i]-'a'])
        {
            ac[p].vis[s[i]-'a']=++cnt;
            init(cnt);
        }
        p=ac[p].vis[s[i]-'a'];
    }
    ac[p].dep=dep;
}
inline void get_fail()
{
    queue<int>que;
    for(int i=0;i<26;i++)
    {
        if(ac[0].vis[i])
        {
            ac[ac[0].vis[i]].fail=0;
            que.push(ac[0].vis[i]);
        }
    }
    while(!que.empty())
    {
        int u=que.front();
        que.pop();
        for(int i=0;i<26;i++)
        {
            if(ac[u].vis[i]!=0)
            {
                ac[ac[u].vis[i]].fail=ac[ac[u].fail].vis[i];
                que.push(ac[u].vis[i]);
            }
            else ac[u].vis[i]=ac[ac[u].fail].vis[i];
        }
    }
}
void query(char s[])
{
    int len=strlen(s),i,j,k,t=0,p=0;
    for(i=0;i<len;i++)
    {
        char c=s[i];
        if('A'<=c&&c<='Z')c+=32;
        else if(!('a'<=c&&c<='z'))
        {
            p=0;continue;
        }
        p=ac[p].vis[c-'a'];
        for(j=p;j;j=ac[j].fail)
        {
            if(ac[j].dep)
            {
                for(k=i-ac[j].dep+1;k<=i;k++)s[k]='*';
            }
        }
    }
}
int main()
{
    int n,T;
    scanf("%d",&T);
    while(T--)
    {
        cnt=0;
        init(0);
        scanf("%d",&n);
        while(n--)
        {
            scanf("%s",s);
            insert(s);
        }
        get_fail();
        getchar();
        cin.getline(s,maxn);
        query(s);
        printf("%s\n",s);
    }
}
View Code

 


 

(上面的板子也不好看●﹏●   用下面的:

例题: 破忒头的匿名信

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+5;

ll f[maxn];
int val[maxn],dep[maxn];
struct AC{
    int tr[maxn][26],cnt;
    int fail[maxn];
    void insert(char s[],int len,int w)
    {
        int p=0;
        for(int i=0;i<len;i++)
        {
            if(!tr[p][s[i]-'a'])tr[p][s[i]-'a']=++cnt;
            p=tr[p][s[i]-'a'];
        }
        dep[p]=len;
        if(!val[p])val[p]=w;
        val[p]=min(val[p],w);
    }
    void getfail()
    {
        queue<int>que;
        for(int i=0;i<26;i++)if(tr[0][i])que.push(tr[0][i]);
        while(!que.empty())
        {
            int p=que.front();que.pop();
            for(int i=0;i<26;i++)
            {
                if(tr[p][i])fail[tr[p][i]]=tr[fail[p]][i],que.push(tr[p][i]);
                else tr[p][i]=tr[fail[p]][i];
            }
        }
    }
    void query(char s[],int len)
    {
        int j,p=0;
        for(int i=1;i<=len;i++)
        {
            j=p=tr[p][s[i]-'a'];
            while(j)
            {
                if(dep[j])f[i]=min(f[i],f[i-dep[j]]+val[j]);
                j=fail[j];
            }
        }
    }
}ac;
char s[maxn];
int main()
{
    int n,w,len;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s%d",s,&w);
        ac.insert(s,strlen(s),w);
    }
    ac.getfail();
    scanf("%s",s+1);
    len=strlen(s+1);
    for(int i=1;i<=len;i++)f[i]=1e16;
    ac.query(s,len=strlen(s+1));
    printf("%lld\n",f[len]==1e16?-1:f[len]);
}
View Code

 

posted @ 2019-10-23 15:53  草丛怪  阅读(157)  评论(0编辑  收藏  举报