首页 > 代码库 > [AC自动机] zoj Searching the String

[AC自动机] zoj Searching the String

题意:

给一个原串,再给n个串,每个串有属性,属性0代表可以重叠,1代表不可以重叠

问每个串出现了多少次

思路:

为了方便建立两个自动机(0的一个,1的一个)

然后可以重叠的很好做,以前都做过

不可重叠的话需要记录两个东西

len[i]代表每个串的长度,used[i]代表每个串在之前出现的位置,初始化-1

然后遍历到的时候对于当前位置 j, 必须j>=used[i]+len[i] 才能算出现,并且更新

需要注意的是:

会出现同样属性并且相同的串。我处理的方式就是排序,按id排序大的在前

然后算一遍大的,用大的赋值给id 小的且串相同的。

代码:

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
using namespace std;
char fuck[123456];
int ans[123456],used[123456],len[123456];
struct word
{
    int x,id;
    char y[7];
} dc[123456];
struct trie
{
    int mark;
    trie *next[27];
    trie *fail;
    trie()
    {
        mark=0;
        memset(next,0,sizeof(next));
        fail=NULL;
    }
};
trie *root0,*root1;
void init(int key,char *v,int id)
{
    trie *p;
    if(key) p=root1;
    else p=root0;
    for(int i=0; v[i]; i++)
    {
        int tep=v[i]-'a';
        if(p->next[tep]==NULL) p->next[tep]=new trie();
        p=p->next[tep];
    }
    p->mark=id;
}
void del(trie *p)
{
    for(int j=0; j<26; j++) if(p->next[j]!=NULL) del(p->next[j]);
    free(p);
}
void getac()
{
    queue<trie*>q;
    q.push(root0);
    while(!q.empty())
    {
        trie *p,*tep;
        p=q.front();
        q.pop();
        for(int i=0; i<26; i++)
        {
            if(p->next[i]!=NULL)
            {
                if(p==root0) p->next[i]->fail=root0;
                else
                {
                    tep=p->fail;
                    while(tep!=NULL)
                    {
                        if(tep->next[i]!=NULL)
                        {
                            p->next[i]->fail=tep->next[i];
                            break;
                        }
                        tep=tep->fail;
                    }
                    if(tep==NULL) p->next[i]->fail=root0;
                }
                q.push(p->next[i]);
            }
        }
    }
    q.push(root1);
    while(!q.empty())
    {
        trie *p,*tep;
        p=q.front();
        q.pop();
        for(int i=0; i<26; i++)
        {
            if(p->next[i]!=NULL)
            {
                if(p==root1) p->next[i]->fail=root1;
                else
                {
                    tep=p->fail;
                    while(tep!=NULL)
                    {
                        if(tep->next[i]!=NULL)
                        {
                            p->next[i]->fail=tep->next[i];
                            break;
                        }
                        tep=tep->fail;
                    }
                    if(tep==NULL) p->next[i]->fail=root1;
                }
                q.push(p->next[i]);
            }
        }
    }
}
void finde(char *v)
{
    trie *p0=root0,*p1=root1;
    for(int i=0; v[i]; i++)
    {
        int tep=v[i]-'a';
        while(p0->next[tep]==NULL && p0!=root0)
            p0=p0->fail;
        p0=p0->next[tep];
        if(p0==NULL) p0=root0;
        trie *q0=p0;
        while(q0!=root0)
        {
            if(q0->mark!=0) ans[q0->mark]++;
            q0=q0->fail;
        }
        while(p1->next[tep]==NULL && p1!=root1)
            p1=p1->fail;
        p1=p1->next[tep];
        if(p1==NULL) p1=root1;
        trie *q1=p1;
        while(q1!=root1)
        {
            if(q1->mark!=0)
            {
                if(i>=used[q1->mark]+len[q1->mark])  //不可重叠的判断
                {
                    ans[q1->mark]++;
                    used[q1->mark]=i;
                }
            }
            q1=q1->fail;
        }
    }
}
int cmp(word a,word b)  //排序的cmp
{
    if(a.x==b.x)
    {
        if(strcmp(a.y,b.y)==0)
        {
            if(a.id>b.id) return 1;
            else return 0;
        }
        else
        {
            if(strcmp(a.y,b.y)>0) return 1;
            else return 0;
        }
    }
    else
    {
        if(a.x>b.x) return 1;
        else return 0;
    }
}
int main()
{
    int cas=1;
    while(scanf("%s",fuck)!=-1)
    {
        int n;
        scanf("%d",&n);
        root0=new trie();
        root1=new trie();
        for(int i=1; i<=n; i++)
        {
            int x;
            char y[12];
            scanf("%d%s",&x,y);
            len[i]=strlen(y);
            init(x,y,i);
            dc[i].x=x;
            strcpy(dc[i].y,y);
            dc[i].id=i;
        }
        memset(ans,0,sizeof(ans));
        memset(used,-1,sizeof(used));
        getac();
        finde(fuck);
        sort(dc+1,dc+1+n,cmp);
        int i;
        for(i=1; dc[i+1].x==1; i++)  //赋值给那些重复的
        {
            if(strcmp(dc[i].y,dc[i+1].y)==0)
                ans[dc[i+1].id]=ans[dc[i].id];
        }
        for(i=i+1; i<n; i++)
        {
            if(strcmp(dc[i].y,dc[i+1].y)==0)
                ans[dc[i+1].id]=ans[dc[i].id];
        }
        printf("Case %d\n",cas++);
        for(int i=1; i<=n; i++) printf("%d\n",ans[i]);
        del(root0);
        del(root1);
        puts("");
    }
    return 0;
}


[AC自动机] zoj Searching the String