AC自动机_重叠与非重叠匹配

  • 可重叠与不可重叠匹配
      比如模式串为aba,字符串为abababab,若可重叠匹配,那么aba出现的次数为三次;若为不可重叠匹配,那么出现的次数为两次: aba / b / aba /b
       AC自动机对于可重叠匹配很方便,直接顺着节点的fail指针一直走就可以.

不可重叠匹配
Searching the String
题意:
有若干个模式串,然后在字符串中查询它们出现的次数.但是0表示可以重叠出现,1表示不可以重叠出现;
题解:
 假设字典树的每个单词尾节点都有个变量为pos,记录最后一次匹配主串的位置;
 对于可重叠匹配,直接顺着自动机的fail指针一直走;
 对于不可重叠匹配,如果当前正在匹配主串的位置-最后一次成功匹配的字符串的位置大于等于单词的长度,那么这样的匹配是可行的;
 比如模式串为aba,字符串为abababab,第一次匹配到aba的位置为2;第二次匹配到aba位置为4,但是4-2<3,所以这次的匹配是无效的;第三次匹配到aba位置为6,6-2=4>=3,成功匹配;所以最后成功匹配次数为2

/*    这题数据有点恶心,模式串会重复出现
input:
ab
4  
0 ab  
1 ab  
0 ab  
1 ab  
output:
Case 1
1
1
1
1

*/  
#include
#include
#include
#include
using namespace std;
const int MAXN=100010;
const int BASE=26;
struct Node
{
    int fail;
    int next[26];
    bool ed;
    int len;
    int id1;
    int id2;
    int pos;
    void init()
    {
        fail=0;
        ed=false;
        len=pos=-1;
        id1=id2=0;
        memset(next,0,sizeof(next));
    }
};
Node trie[600005];
int trie_s;
int *x[MAXN];
char str[MAXN];
void put(char *str,int choose,int id)
{
    int p=1;
    int len=strlen(str);
    for(int i=0;i que;
    int son,p=1,temp;
    que.push(p);
    while(!que.empty())
    {
        int curr=que.front();
        que.pop();
        for(int i=0;i<26;i++)
        {
            son=trie[curr].next[i];
            if(son)
            {
                if(curr==1) trie[son].fail=1;
                else
                {
                    temp=trie[curr].fail;
                    while(temp!=0)
                    {
                        if(trie[temp].next[i])
                        {
                            trie[son].fail=trie[temp].next[i];
                            break;
                        }
                        temp=trie[temp].fail;
                    }
                    if(temp==0) trie[son].fail=1;
                }
                que.push(son);
            }
        }
    }
}
void query(char *str)
{
    int len=strlen(str);
    int p=1,temp;
    for(int i=0;i=trie[temp].len))
                {
                    trie[temp].id2=trie[temp].id2+1;
                    trie[temp].pos=i;
                }
            }
            temp=trie[temp].fail;
        }
    }
}
int main()
{
    int n,choose,cas=1;
    char ss[10];
    while(scanf("%s",str)!=EOF)
    {
        scanf("%d",&n);
        trie[1].init();
        trie_s=1;
        for(int i=1;i<=n;i++)
        {
            scanf("%d %s",&choose,ss);
            put(ss,choose,i);
        }
        getFail();
        query(str);
        printf("Case %d\n",cas++);
        for(int i=1;i<=n;i++)
        {
            printf("%d\n",*x[i]);
        }
        printf("\n");
    }
    return 0;
}

你可能感兴趣的:(AC自动机_重叠与非重叠匹配)