poj 4052(ac自动机)

题意:自己百度吧!!

分析:就是通过它的fail指针来找出它的子串就行了,这题其实不难的。这好像还是金华邀请赛的题哦!

代码实现:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<queue>
using namespace std;
struct node{
    int next[26];
    int fail;
    int num;
    void init()
    {
        memset(next,0,sizeof(next));
        fail=0;
        num=0;
    }
}a[3000010];
char keyword[2600][1200];
char S[5200001],temp[5200001];
int visited[3505];
int tot,n;
int ok[3000010];

void chushihua()//初始化
{
    tot=0;
    a[0].init();
    memset(visited,0,sizeof(visited));
}

void insert(char *str,int biaohao)//建立字典树
{
    int index,p=0;
    for(;*str!='\0';str++)
    {
        index=*str-'A';
        if(a[p].next[index]==0)
        {
            a[++tot].init();
            a[p].next[index]=tot;
        }
        p=a[p].next[index];
    }
    a[p].num=biaohao;
}

void build_fail()//建立trie图
{
    queue<int>Q;
    int p,cur,son,i;
    Q.push(0);
    while(!Q.empty())
    {
        p=Q.front();
        Q.pop();
        for(i=0;i<26;i++)
        {    
            if(a[p].next[i]!=0)
            {
                son=a[p].next[i];
                cur=a[p].fail;
                if(p==0)
                    a[son].fail=0;
                else
                {
                    while(cur&&a[cur].next[i]==0)
                        cur=a[cur].fail;
                    a[son].fail=a[cur].next[i];
                }
                Q.push(son);
            }
            else
                a[p].next[i]=a[a[p].fail].next[i];
        }
    }
}

void change(char str[])
{
    int i,len=0,k=0;
    for(i=0;str[i]!='\0';i++)
    {
        if(str[i]>='A'&&str[i]<='Z')
            temp[len++]=str[i];
        else 
        {
            i++;
            k=0;//开始的时候这里没加,一直wa,细节啊
            k=k+str[i]-'0';
            i++;
            while(str[i]>='0'&&str[i]<='9')
            {
                k=k*10+str[i]-'0';
                i++;
            }
            while(k--)
                temp[len++]=str[i];
            i++;
            
        }
    }
    temp[len]='\0';
    strcpy(str,temp);
}

void solve1()//在主串里出现过的全部标记了
{
    int i,index,p=0,j;
    for(i=0;S[i]!='\0';i++)
    {
        index=S[i]-'A';
        p=a[p].next[index];
        if(a[p].num)
        {
            visited[a[p].num]=1;
            continue;//它的子串肯定就不用标记了
        }
        for(j=p;j!=0&&ok[j]==0;j=a[j].fail)
        {
            ok[j]=1;
            visited[a[j].num]=1;
        }
    }
}

void solve2(char S[],int biaohao)//去掉子串
{
    int i,index,p=0,j;
    for(i=0;S[i]!='\0';i++)
    {
        index=S[i]-'A';
        p=a[p].next[index];
        for(j=p;j!=0&&ok[j]==0;j=a[j].fail)
        {
            if(a[j].num&&a[j].num!=biaohao)
            {
                visited[a[j].num]=0;
                ok[j]=1;
            }
        }
    }
}

int main()
{
    int T,i,res;
    scanf("%d",&T);
    while(T--)
    {
        chushihua();
        res=0;
        scanf("%d",&n);
        getchar();
        for(i=1;i<=n;i++)
        {
            scanf("%s",keyword[i]);
            change(keyword[i]);//把畸形的字符串变成正常的
            insert(keyword[i],i);
        }
        build_fail();
        scanf("%s",S);
        change(S);
        memset(ok,0,sizeof(ok));
        solve1();
        memset(ok,0,sizeof(ok));
        for(i=1;i<=n;i++)
            if(visited[i]==1)
               solve2(keyword[i],i);
        for(i=1;i<=n;i++)
            if(visited[i]==1)
                res++;
        printf("%d\n",res);
    }
    return 0;
}

 

posted on 2013-08-05 12:55  后端bug开发工程师  阅读(901)  评论(2编辑  收藏  举报

导航