hdu 6138 Fleet of the Eternal Throne(AC自动机)

来源:互联网 发布:惠州网络推广公司 编辑:程序博客网 时间:2024/06/08 10:40

http://acm.hdu.edu.cn/showproblem.php?pid=6138
题目大意:给出n个字符串后,会有q个询问,每个询问会输入两个数,记为x,y。然后要求的是,x,y的 最长公共子串,而且这个最长公共子串要是n个字符串中某个字符串的前缀。输出这个串的长度。
解题思路:这题的题意很明确,首先我们要求出x,y串的公共子串,然后要在n个字符串中出现过。这样就可以用的AC自动机。AC自动机原来是用来多模式匹配的,原来每个节点维护的值有一个标记是否是一个完整的字符串,然而由于该题是要前缀长度,我们就要队节点维护的值有所改进,每个节点维护其所代表的前缀的长度即可。这样的话,我们可以用这n个字符串构建字典树,然后通过BFS找到每个节点对应的fail指针,接下来,由于我们要找的是第x个字符串和第y个字符串的最长公共字串长度,且该字串是n个字符串中某个字符串的前缀。因此我们需要用第x个字符串和第y个字符串在字典树上进行一个匹配。当第x个字符串去匹配的时候,我们要做的就是把所有在匹配时经过的节点都标记一下。代表这些节点到字典树的根所代的字符串既是某个字符串的前缀,还在第x个字符串中。同理我们让第y个字符串在按相同的方法跑一遍AC自动机,有所不同的是,第一个串跑完之后已经留下标记,我们可以在第2个串跑的时候,直接通过检测标记来确定某个节点所代表的字符串是不是x,y的共同子串。然后边检测边求解答案就可以了。

#include <bits/stdc++.h>using namespace std;struct Trie{    int len,flag;    Trie *fail;    Trie *child[26];    Trie()    {        flag = 0;        len = 0;        fail = NULL;        for(int i=0; i<26; i++)            child[i] = NULL;    }};Trie *root,*current,*temp;string str[100005];int ans;void _insert(string s){    current = root;    for(int i=0; i<s.length(); i++)    {        int index = s[i] - 'a';        if(current->child[index] == NULL)        {            temp = new Trie;            temp->len = current->len+1;            current->child[index] = temp;        }        current = current->child[index];       // (current->len)++;    }}void Find_fail(){    queue<Trie*> Q;    Q.push(root);    while(!Q.empty())    {        current = Q.front();        Q.pop();        for(int i=0; i<26; i++)        {            if(current->child[i]!=NULL)            {                if(current==root)                    current->child[i]->fail = root;                else                {                    Trie *p = current->fail;                    while(p)                    {                        if(p->child[i])                        {                            current->child[i]->fail = p->child[i];                            break;                        }                        p=p->fail;                    }                    if(p==NULL)                        current->child[i]->fail = root;                }                Q.push(current->child[i]);            }        }    }}void _search(string s,int f){    current = root;    for(int i=0; i<s.length(); i++)    {        int index = s[i]-'a';        while(!current->child[index]&&current!=root)            current = current->fail;        current = current->child[index];        if(!current)  current = root;        temp = current;        while(temp!=root)        {            temp->flag = f;            temp = temp->fail;        }    }}void AC_authomation(string s,int f){    current = root;    for(int i=0; i<s.length(); i++)    {        int index = s[i]-'a';        while(!current->child[index]&&current!=root)            current = current->fail;        current = current->child[index];        if(!current)  current = root;        temp = current;        while(temp!=root)        {            if(temp->flag == f)            {                ans = max(temp->len,ans);            }            temp = temp->fail;        }    }}int main(){    int T;    scanf("%d",&T);    while(T--)    {        int n,q,x,y;        root = new Trie;        scanf("%d",&n);        for(int i=1; i<=n; i++)        {            cin>>str[i];            _insert(str[i]);        }        Find_fail();        scanf("%d",&q);        for(int i=1; i<=q; i++)        {            ans = 0;            scanf("%d %d",&x,&y);            _search(str[x],i);            AC_authomation(str[y],i);            printf("%d\n",ans);        }    }    return 0;}