`

杭电 hdu 1277 全文检索

阅读更多
第二次
/* THE PROGRAM IS MADE BY PYY */
/*----------------------------------------------------------------------------//
    Copyright (c) 2011 panyanyany All rights reserved.

    URL   : http://acm.hdu.edu.cn/showproblem.php?pid=1277
    Name  : hdu  1277 ( 全文检索 )

    Date  : Friday, August 19, 2011
    Time Stage : Many hours

    Result:
4450219	2011-08-19 14:53:51 Accepted 1277 109MS	19256K	4903 B C++ pyy


Test Data:

Review:
嗯,第二次做 了,感觉确实比第一次好……
//----------------------------------------------------------------------------*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))

#define infinity    0x7f7f7f7f
#define minus_inf    0x80808080

#define MAXSIZE 60006
#define LESSMAX	10009

typedef struct tagNODE {
	int cnt, num ;
	struct tagNODE * fail, * child[10] ;
} NODE ;

#define root stack[0]

NODE * tmp, * tmpFail, * newNode, * parntNode, * childNode ;
NODE * queue[LESSMAX * 100], * stack[LESSMAX * 100] ;

char model[MAXSIZE], pattn[LESSMAX] ;
int m, n, num ;
int head, tial ;	// for queue
int stkPtr ;		// for stack 
int sequence[LESSMAX] ; // 按顺序记录能匹配的关键字序号
int iseq ;			// for sequence

void makeTrie ()
{
	int i, j ;
	int len = strlen (pattn) ;

	tmp = root ;

	for (i = 0 ; i < len ; ++i)
	{
		j = pattn[i] - '0' ;
		if (!tmp->child[j])
		{
			newNode			= (NODE *) calloc (1, sizeof (NODE)) ;
			stack[stkPtr++]	= newNode ;
			tmp->child[j]	= newNode ;
		}
		tmp = tmp->child[j] ;
	}
	tmp->num = num ;
	++tmp->cnt ;
}

void makeFail ()
{
	int i ;
	head = tial = 0 ;

	tmp = root ;
	for (i = 0 ; i < 10 ; ++i)
	{
		if (tmp->child[i])
		{
			tmp->child[i]->fail = root ;
			queue[tial++] = tmp->child[i] ;
		}
	}

	while (head < tial)
	{
		parntNode = queue[head++] ;
		for (i = 0 ; i < 10 ; ++i)
		{
			if (childNode = parntNode->child[i])
			{
				tmpFail = parntNode->fail ;		// 儿子的错误要从老子身上去总结
				while (tmpFail && !tmpFail->child[i])
					tmpFail = tmpFail->fail ;
				if (tmpFail)	// 找到了某位祖宗跟自己同名同姓的孩子
					childNode->fail = tmpFail->child[i] ;	// 自己失败了就让他接着干吧
				else			// 找到了人类的始祖----猴子了……
					childNode->fail = root ;
				queue[tial++] = childNode ;
			}
		}
	}
}

void ACAutomation ()
{
	int i, j ;
	int len = strlen (model) ;

	tmp = root ;
	for (i = 0 ; i < len ; ++i)
	{
		j = model[i] - '0' ;

		// 一开始的时候,用了(!tmp->child[j] && tmp) 来判断,结果只要字符失配,就出现内存访问
		// 错误,因为当tmp不断向根部回溯的时候,当tmp = root ,并且tmp->child[j] == 0 的时候,
		// 下一句便是tmp = tmp->fail,使得tmp 指向根部的失败指针,也就是tmp = 0 ;
		// 然后再判断tmp->child[j] 的时候,就出现内存访问错误了。
		// 于是后来改成了(tmp && !tmp->child[j]),嗯,这一句是没错了,但下一句却错了。
		// tmp = (tmp->child[j]) ? tmp->child[j] : root ; 这一句也出现了上面的问题

		// 我很郁闷,感觉也没有什么问题啊,无奈回头看了看以前的代码,发现原来是:
		// (tmp != root && !tmp->child[j]) 
		// 这有什么不同呢?也就是说,当失败指针使tmp 指向根部时,便不再判断根部的孩子中是否
		// 有匹配项了。于是有人便会问:那不就漏了一次查找了么?

		// 不在while循环里判断,是因为下面的一句可以判断:
		// tmp = (tmp->child[j]) ? tmp->child[j] : root ;
		// 在这里判断根部的孩子也没有匹配项之后,tmp 就正式指向根部,准备从头开始对model 中下
		// 一个字符进行匹配了

		// 当然了,其实这样也是可以的:while (tmp && !tmp->child[j]),不过后面的代码便不得不
		// 有点啰嗦了,一段啰嗦的代码,显然不是程序员所追求的……起码现在如此≈≈≈⌒_⌒

		while (tmp != root && !tmp->child[j])	// 向源头方向寻找匹配项,或者统统失配,换下一个字符
			tmp = tmp->fail ;
		tmp = (tmp->child[j]) ? tmp->child[j] : root ;	// 如果统统失配,当然要从根部重新开始了

		tmpFail = tmp ;	// 给tmp弄个分身,艰苦的“人口普查”工作就交给他了……
		while (tmpFail->cnt)
		{
			sequence[iseq++] = tmpFail->num ;
			tmpFail->cnt = 0 ;
			tmpFail = tmpFail->fail ;
		}
	}
}

void recycle ()
{
	while (stkPtr)
	{
		free (stack[--stkPtr]) ;
	}
}

int main ()
{
	int i ;
	int len ;
	while (scanf ("%d%d", &m, &n) != EOF)
	{
		len = 0 ;
		iseq = 0 ;

		scanf ("%s", model) ;
		getchar () ;
		len = strlen (model) ;
		for (i = 1 ; i < m ; ++i)
		{
			scanf ("%s", model + len * i) ;
			getchar () ;
		}
		getchar () ;

		stkPtr		= 1 ;
		stack[0]	= (NODE *) calloc (1, sizeof (NODE)) ;

		for (i = 0 ; i < n ; ++i)
		{
			scanf ("[Key No. %d] %s", &num, pattn) ;
//			printf ("%s\n", pattn) ;
			getchar () ;
			makeTrie () ;
		}
		makeFail () ;
		ACAutomation () ;

		if (iseq)
		{
			printf ("Found key:") ;
			for (i = 0 ; i < iseq ; ++i)
				printf (" [Key No. %d]", sequence[i]) ;
			puts ("") ;
		}
		else
			puts ("No key can be found !") ;

		recycle () ;
	}
	return 0 ;
}



第一次

/* THE PROGRAM IS MADE BY PYY */
/*----------------------------------------------------------------------------//
    Copyright (c) 2011 panyanyany All rights reserved.

    URL   : http://acm.hdu.edu.cn/showproblem.php?pid=1277
    Name  : hdu  1277 ( 全文检索 )

    Date  : Friday, June 24, 2011
    Time Stage : Many days

    Result:
4088782	2011-06-24 22:10:34	Accepted	1277
125MS	19304K	4346 B
C++	pyy

4088768	2011-06-24 22:05:15 Wrong Answer 1277 0MS 240K 4218 B C++ pyy


Test Data:

Review:
//----------------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define SZ_MODEL    60001
#define SZ_PATN     66
#define NUM_PATN    10001
#define NUM_ELEM    10

#define FIRST_ELEM  ('0')

typedef struct tagNODE {
    int cnt, id ;
    struct tagNODE *fail, *child[NUM_ELEM] ;
} NODE ;

NODE *trie[NUM_PATN * SZ_PATN], *queue[NUM_PATN * SZ_PATN], *p, *root ;

char amodel[SZ_MODEL], apattern[SZ_PATN] ;
int line, keyword, len, num, count, cursor, find ;

// 两个数组是必须的,一个用来记录先后顺序,一个用来判断是否已经出现过
int indices[NUM_PATN], repeat[NUM_PATN] ;

void initialization ()
{
    len = 0 ;
    cursor = 0 ;
    find = 0 ;
    trie[cursor++] = (NODE *) calloc (1, sizeof (NODE)) ;
    memset (repeat, 0, sizeof (repeat)) ;
    root = *trie ;
}

void recycle ()
{
    while (cursor--)
    {
        free (trie[cursor]) ;
    }
}

void makeTrie ()
{
    char *s = apattern ;
    int index ;
    
    p = root ;
    
    while (*s)
    {
        index = *s++ - FIRST_ELEM ;
//        printf ("%d ", index) ;
        if (! (p->child[index]))
        {
            trie[cursor] = (NODE *) calloc (1, sizeof (NODE)) ;
            memset (trie[cursor], 0, sizeof (trie[cursor])) ; //-----------------------------
            p->child[index] = trie[cursor++] ;
        }
        p = p->child[index] ;
    }
    ++p->cnt ;	// 多余的变量
    p->id = num ;
}

void makeFail ()
{
    int head, tial, i ;
    NODE *tmpFail ;
    
    head = tial = 0 ;   // initialize index
    
    root->fail = 0 ;
    
    for (i = 0 ; i < NUM_ELEM ; ++i)
    {
        if (root->child[i])
        {
            root->child[i]->fail = root ;
            queue[tial++] = root->child[i] ;
        }
    }
    
    while (head != tial)
    {
        p = queue[head++] ;
        for (i = 0 ; i < NUM_ELEM ; ++i)
        {
            if (p->child[i])
            {
                queue[tial++] = p->child[i] ;   // enqueue
                
                //-------------- make failure pointer-----------------------
                tmpFail = p->fail ;
                while (tmpFail)
                {
                    if (tmpFail->child[i])
                    {
                        p->child[i]->fail = tmpFail->child[i] ;
                        break ;
                    }
                    tmpFail = tmpFail->fail ;
                }
                
                if (!tmpFail)
                    p->child[i]->fail = root ;
            }
        }
    }
}

void acAutomation ()
{
    NODE *tmp ;
    char *s = amodel ;
    int index ;
    
    p = root ;
    
    while (*s)
    {
        index = *s++ - FIRST_ELEM ;

        while (p->child[index] == NULL && p != root)
            p = p->fail ;
        
		/* 此处切忌使用 p = (p == root) ? p : p->child[index] ; 这样的语句。
		   p 的下一个值不能通过 是否与 root 相等来判断
		 */
        p = (p->child[index] == NULL) ? p : p->child[index] ;
        
        tmp = p ;
        
        while (tmp->id)
        {
            if (!repeat[tmp->id])
            {
                indices[find++] = tmp->id ;
                repeat[tmp->id] = 1 ;
            }

            tmp->id = 0 ;
            tmp = tmp->fail ;
        }
    }
}

int main ()
{
    int i ;
    char c ;
    
//    freopen ("test.txt", "r", stdin) ;

    while (scanf ("%d%d", &line, &keyword) != EOF)
    {
        initialization () ;
        
        while (line--)
        {
            scanf ("%s%c", amodel + len, &c) ;	
			// %c 和 c 是读取 '\n'用的,
			// 不能这样写 : scanf ("%s\n", amodel + len) ; 下同
            len = strlen (amodel) ;
        }
        
        getchar () ;	// 注意吸收掉一个空行
        
        while (keyword--)
        {
            scanf ("[Key No. %d] %s%c", &num, apattern, &c) ;
            makeTrie () ;
        }
        makeFail () ;
        
        acAutomation () ;
        
        if (find)
        {
            printf ("Found key:") ;
            for (i = 0 ; i < find ; ++i)
                printf (" [Key No. %d]", indices[i]) ;
            puts ("") ;
        }
        else
            puts ("No key can be found !") ;
            
        recycle () ;
    }

    return 0 ;
}

0
4
分享到:
评论

相关推荐

    杭电HDU ACM培训课件

    《杭电HDU ACM培训课件》是一份珍贵的学习资源,源自杭州电子科技大学的ACM竞赛培训课程。这些课件是官方论坛上分享的,旨在为那些积分不足无法获取资源或者对ACM编程竞赛感兴趣的初学者提供帮助。下面将详细阐述这...

    杭电HDU2050题的ac程序

    一个十分简单的程序,能够ac杭电hdu的第2050题,无注释,简单明了

    计算机网络复习大纲_杭电hdu.pdf

    计算机网络复习大纲_杭电hdu.pdf

    计算机网络复习大纲_杭电hdu整理.pdf

    计算机网络复习大纲_杭电hdu整理.pdf

    计算机网络复习大纲_杭电hdu参考.pdf

    计算机网络复习大纲_杭电hdu参考.pdf

    杭电HDU ACM 1005

    杭电ACM1005题源代码,AC了的程序,无问题……

    杭电操作系统实验 HDU操作系统实验.zip

    杭电操作系统实验 HDU操作系统实验.zip杭电操作系统实验 HDU操作系统实验.zip杭电操作系统实验 HDU操作系统实验.zip杭电操作系统实验 HDU操作系统实验.zip杭电操作系统实验 HDU操作系统实验.zip杭电操作系统实验 HDU...

    计算机网络复习大纲_杭电hdu借鉴.pdf

    计算机网络是信息技术领域的重要组成部分,它涉及到数据的传输、交换和资源共享。本复习大纲主要涵盖了计算机网络的基础概念、体系结构、通信方式以及不同类型的网络。 首先,计算机网络的五层协议体系机构是理解...

    杭电ACMhdu1163

    【标题】:杭电ACMhdu1163 【描述】:这是一道源自杭州电子科技大学(Hangzhou Dianzi University,简称HDU)的ACM编程竞赛题目,编号为1163。这类问题通常需要参赛者利用计算机编程解决数学、逻辑或算法上的挑战,...

    hdu_ACM.rar_ACM_hdu_hdu acm_hdu_ACM_杭电ACM

    杭电hdu acm资料所用杭电的acm题

    HDU杭电 计算机网络实验报告

    这份"HDU杭电 计算机网络实验报告"压缩包提供了丰富的实验材料,涵盖了多个关键的网络技术,包括交换机配置、路由协议、地址转换(NAT)、访问控制列表(ACL)以及动态主机配置协议(DHCP)等。以下是这些实验报告所...

    杭电(HDU)ACM题解

    HDU2000至2099题的题目以及AC代码(含思路) 适合刚刚接触ACM的同学哦~ emmmm凑字

    hdu.rar_HDU 1089.cpp_OJ题求和_hdu_horsekw5_杭电obj

    【标题】"hdu.rar_HDU 1089.cpp_OJ题求和_hdu_horsekw5_杭电obj" 提供的信息是关于一个压缩文件,其中包含了一个名为 "HDU 1089.cpp" 的源代码文件,这个文件是为了解决杭州电子科技大学(Hangzhou Dianzi ...

    杭电(HDU) OJ离线版

    为了方便广大没有网络的朋友.......

    HDU 杭电操作系统实验 (通过验收)

    包含实验内容:对应实验要求上的1/2/3/5实验,分别为setName/setNice,petree输出进程,模拟shell,进程通信,文件系统。包含全部实验源代码和详尽的word实验报告。同时包含在线PTA编程题目:进程模拟,模拟进程调度...

    acm课件搜索(杭电)(HDU)

    "acm课件搜索(杭电)(HDU)"这个主题聚集了相关的学习材料,特别是针对搜索算法的讲解,旨在帮助学生快速掌握并应用这些技术。 搜索算法在ACM竞赛中扮演着至关重要的角色,常见的搜索策略包括深度优先搜索(DFS)...

    acm课件简单数学题(杭电)(HDU)

    在ACM(国际大学生程序设计竞赛,International Collegiate Programming Contest,简称ICPC)中,数学是至关重要的一部分,尤其是在解决杭电(Hangzhou Dianzi University,简称HDU)的题目时。本课件"acm课件简单...

Global site tag (gtag.js) - Google Analytics