hdu 2222 Keywords Search (ac_automaton)

ac自动机:点击打开ac自动机资料

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

const int MAXN = 500010;

struct Trie_Node
{
    Trie_Node* fail;
    Trie_Node* pNext[26];
    int kcount;
    Trie_Node()
    {
        fail = NULL;
        kcount  = 0;
        memset(pNext, NULL, sizeof(pNext));
    }
};

Trie_Node* proot;
Trie_Node* q[MAXN];
int head, tail;
char s1[1000010], s2[110];

void Insert_Trie(char* str)//建字典树
{
    Trie_Node* p = proot;
    for(; *str; str++)
    {
        int j = *str - 'a';
        if(p->pNext[j] == NULL)
            p->pNext[j] = new Trie_Node;
        p = p->pNext[j];
    }
    p->kcount++;
}

void Build_ac_automaton_fail()//建立所有节点的失败指针
{
	head = tail = 0;
	proot->fail = NULL;//根节点的失败指针为空
	q[tail++] = proot;//首先把根节点入队
	while (head != tail)
	{
		Trie_Node* temp = q[head++];
		Trie_Node* p = NULL;
		for (int i = 0; i < 26; ++i)
		{
			if (temp->pNext[i] != NULL)
			{
				if(temp == proot)//如果temp为根节点,则其子节点的失败指针指向根节点
					temp->pNext[i]->fail = proot;
				else
				{
					p = temp->fail;//否则,p为temp的失败指针
					while (p != NULL)//如果p不为空,查看其子节点p->pNext[i]是否跟temp->pNext[i]相同,仔细考虑"i"的含义
					{
						if (p->pNext[i] != NULL)//如果p->pNext[i]不为空
						{
							temp->pNext[i]->fail = p->pNext[i];//则,temp->pNext[i]的失败指针指向p->pNext[i]
							break;//跳出while循环并把temp->pNext[i]进队。
						}
						p = p->fail;//如果p->pNext[i]为空,则p为p的失败指针
					}
					if(p == NULL)//如果p为空,则把p->pNext[i]的失败指针指向根节点
						temp->pNext[i]->fail = proot;
				}
				q[tail++] = temp->pNext[i];
			}
		}
	}
}

int Query(char* str)
{
	int i = 0;
	int sum = 0;
	Trie_Node* p = proot;//这个p指向的是待查字符串的所查的位置,
	while (str[i])
	{
		int j = str[i] - 'a';
		while (p->pNext[j] == NULL && p != proot)//如果p是叶子节点,则把p指向p的失败指针
			p = p->fail;
		p = (p->pNext[j] == NULL) ? proot : p->pNext[j];//如果j所代表的字符所在的节点为空则p赋值为根节点,否则让p 为p->pNext[j]
		Trie_Node* temp = p;

		while (temp != proot && temp->kcount != -1)//本题只是让查出有多少单词种类,如果要查有多少单词temp->kcount != -1要删去,以及下面
		{
			sum += temp->kcount;
			temp->kcount = -1;//如果要查有多少单词数,这一句也要删去
			temp = temp->fail;
		}
		i++;
	}
	return sum;
}

int main()
{
	int T;
	int n;
	scanf("%d", &T);
	while (T--)
	{
		proot = new Trie_Node;
		scanf("%d", &n);
		while (n--)
		{
			scanf("%s", s2);
			Insert_Trie(s2);
		}
		Build_ac_automaton_fail();
		scanf("%s", s1);
		printf("%d\n", Query(s1));
	}
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值