失败的三叉树+ac自动机(TLE可能是插入时未进行平衡操作)

TLE,TLE,各种姿势还是TLE,改递归为非递归,还是TLE。

求解。

#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
using namespace std;
typedef int Nodelink;
const int maxn = 1000101;//内存池大小
Nodelink Node[maxn][3];   //三叉树的节点,预开内存的速度是动态开不可比拟的(TLE了一晚的教训)。
Nodelink fail[maxn];
int cnt[maxn];   //以该节点为结束的字符串的数目。
char elem[maxn];   //节点保存的字符。
int top;   //模拟内存池地址
int link[maxn];
Nodelink newNode(char ch) //创建一个节点
{
	top ++;
	Node[top][0] = Node[top][1] = Node[top][2] = 0;
	cnt[top] = 0;
	elem[top] = ch;
	return top;
}

char sub[5][6] = {"","nihao","hao","hs","hsr"};

void insert(char str[], int idx) //插入模式串
{
	int len = strlen(str);
	Nodelink p = 1;
	for(int i = 0; i < len; i++) {
		if(!Node[p][2])
			Node[p][2] = newNode(str[i]);
		p = Node[p][2];
		while(elem[p] != str[i]) { //二叉树插入元素,保证有序
			if(str[i] < elem[p]) {
				if(!Node[p][0]) Node[p][0] = newNode(str[i]);
				p = Node[p][0];
			}
			else {
				if(!Node[p][1]) Node[p][1] = newNode(str[i]);
				p = Node[p][1];
			}
		}
	}
	cnt[p] = idx; //以编号为p的结点为结尾的模式串的输入序号。
}

char str[30];
void print(Nodelink p, int len) //输出模式串
{
	if(Node[p][0])
		print(Node[p][0], len);
	str[len] = elem[p];

	if(cnt[p]) {
		str[len + 1] = '\0';
		for(int i = 0; i < cnt[p]; i++)
			printf("%s\n", str);
	}

	if(Node[p][2])
		print(Node[p][2], len + 1);

	if(Node[p][1])
		print(Node[p][1], len);
}
queue <int> q;

int findFail(Nodelink fp, Nodelink p) //查找合适p结点的fail点
{
	if(Node[fp][0] && findFail(Node[fp][0], p))
		return 1;
	if(elem[fp] == elem[p])
	{
		fail[p] = fp;
		return 1;
	}
	if(Node[fp][1] && findFail(Node[fp][1], p))
		return 1;
	return 0;
}
void travelPre(Nodelink p, Nodelink pre) 
{
	if(Node[p][0])
		travelPre(Node[p][0], pre);
	Nodelink tmp = fail[pre];
	while(tmp && !findFail(Node[tmp][2], p))
		tmp = fail[tmp];
	if(tmp == 0)
		fail[p] = 1;
	q.push(p);
	if(Node[p][1])
		travelPre(Node[p][1], pre);
}
void getFail() //生成fail指针
{
	while(!q.empty()) q.pop();
	q.push(1);
	fail[1] = 0;
	while(!q.empty())
	{
		Nodelink pre = q.front();
		q.pop();
		if(Node[pre][2])
			travelPre(Node[pre][2], pre);
	}
}
int matchCH(char ch, Nodelink p, Nodelink &pre, int idx)
{
	if(Node[p][0] && matchCH(ch, Node[p][0], pre, idx))return 1;
	if(elem[p] == ch)
	{
		pre = p;
		int fp = p;
		while(fp) //查找是否含有以元素elem[p]结尾的模式串。
		{
		if(cnt[fp])
			printf("%s matches string end at  %d.\n", sub[cnt[p]] ,idx);
		fp = fail[fp];
		}
		return 1;
	}
	if(Node[p][1] && matchCH(ch, Node[p][1], pre, idx))return 1;
	return 0;
}
void match(char pattern[])
{
	int idx = 0;
	Nodelink p = 1;
	while(idx < strlen(pattern))
	{
		while(p && !matchCH(pattern[idx] , Node[p][2], p, idx))
		{
			p = fail[p];
		}
		if(p == 0) p = 1;
		idx ++;
	}
}
int main()
{
	top = 0;
	newNode('\0');
	char pattern[] = "sdmfhsgnshejfgnihaofhsrnihao";
	for(int i = 1; i < 5; i++)
		insert(sub[i], i);
	getFail();
	//print(Node[1][2], 0);
	match(pattern);
return 0;
}

hdoj-2222题没过的代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
using namespace std;
typedef int Nodelink;
const int maxn = 1000101;//内存池大小
Nodelink Node[maxn][3];   //三叉树的节点,预开内存的速度是动态开不可比拟的(TLE了一晚的教训)。
Nodelink fail[maxn];
int cnt[maxn];   //以该节点为结束的字符串的数目。
char elem[maxn];   //节点保存的字符。
int top;   //模拟内存池地址
char str[60];
char pattern[1000010];
Nodelink newNode(char ch) //创建一个节点
{
    top ++;
    Node[top][0] = Node[top][1] = Node[top][2] = 0;
    cnt[top] = 0;
    elem[top] = ch;
    return top;
}


void insert(char str[]) //插入模式串
{
    int len = strlen(str);
    Nodelink p = 1;
    for(int i = 0; i < len; i++) {
        if(!Node[p][2])
            Node[p][2] = newNode(str[i]);
        p = Node[p][2];
        while(elem[p] != str[i]) { //二叉树插入元素,保证有序
            if(str[i] < elem[p]) {
                if(!Node[p][0]) Node[p][0] = newNode(str[i]);
                p = Node[p][0];
            }
            else {
                if(!Node[p][1]) Node[p][1] = newNode(str[i]);
                p = Node[p][1];
            }
        }
    }
    cnt[p] ++; //以编号为p的结点为结尾的模式串的输入序号。
}


queue <int> q;


int findFail(Nodelink fp, Nodelink p) //查找合适p结点的fail点
{
    if(Node[fp][0] && findFail(Node[fp][0], p))
        return 1;
    if(elem[fp] == elem[p])
    {
        fail[p] = fp;
        return 1;
    }
    if(Node[fp][1] && findFail(Node[fp][1], p))
        return 1;
    return 0;
}
void travelPre(Nodelink p, Nodelink pre)
{
    if(Node[p][0])
        travelPre(Node[p][0], pre);
    Nodelink tmp = fail[pre];
    while(tmp && !findFail(Node[tmp][2], p))
        tmp = fail[tmp];
    if(tmp == 0)
        fail[p] = 1;
    q.push(p);
    if(Node[p][1])
        travelPre(Node[p][1], pre);
}
void getFail() //生成fail指针
{
    while(!q.empty()) q.pop();
    q.push(1);
    fail[1] = 0;
    while(!q.empty())
    {
        Nodelink pre = q.front();
        q.pop();
        if(Node[pre][2])
            travelPre(Node[pre][2], pre);
    }
}
int ans = 0;
int matchCH(char ch, Nodelink p, Nodelink &pre)
{
    if(Node[p][0] && matchCH(ch, Node[p][0], pre))return 1;
    if(elem[p] == ch)
    {
        pre = p;
        int fp = p;
        while(fp > 1) //查找是否含有以元素elem[p]结尾的模式串。这一段导致TLE
        {
        ans += cnt[fp];
        fp = fail[fp];
        }
        return 1;
    }
    if(Node[p][1] && matchCH(ch, Node[p][1], pre))return 1;
    return 0;
}
void match(char pattern[])
{
    int idx = 0;
    Nodelink p = 1;
    int len = strlen(pattern);
    while(idx < len)
    {
        while(p && !matchCH(pattern[idx] , Node[p][2], p))
        {
            p = fail[p];
        }
        if(p == 0) p = 1;
        idx ++;
    }
}
int main()
{
    int t, n;
    scanf("%d", &t);
    while(t--)
    {
        top = 0;
        ans = 0;
        newNode('\0');
        scanf("%d", &n);
        for(int i = 0; i < n; i++)
        {
            scanf("%s",str);
            insert(str);
        }
        scanf("%s", pattern);
        getFail();
        match(pattern);
        printf("%d\n", ans);
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值