hdu 2846 Repository 字典树的一种变形

Repository

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 2633    Accepted Submission(s): 1028

Problem Description

When you go shopping, you can search in repository for avalible merchandises by the computers and internet. First you give the search system a name about something, then the system responds with the results. Now you are given a lot
merchandise names in repository and some queries, and required to simulate the process.

Input

There is only one case. First there is an integer P (1<=P<=10000)representing the number of the merchanidse names in the repository. The next P lines each contain a string (it‘s length isn‘t beyond 20,and all the letters are lowercase).Then
there is an integer Q(1<=Q<=100000) representing the number of the queries. The next Q lines each contains a string(the same limitation as foregoing descriptions) as the searching condition.

Output

For each query, you just output the number of the merchandises, whose names contain the search string as their substrings.

Sample Input

20
ad
ae
af
ag
ah
ai
aj
ak
al
ads
add
ade
adf
adg
adh
adi
adj
adk
adl
aes
5
b
a
d
ad
s

Sample Output

0
20
11
11
2

我的AC状态,,我总感觉自己好笨的。。脑子不太灵活,第一次写的时候超时了,,来说一下思路吧,,就是把一个字符串abcde,分别拆成abcde,bcde,cde,de,e,存到字典树里,因为会出现会abcab这样的字符串,他的字串有俩个ab开头的,,所以得在结构体里加上一个id标签,,把id设为最后一个存到字典树里的字符串。看代码就知道啦,很容易懂的

下面是AC代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 20000
struct Trie{
	int count;		//储存相同字符串的数目
	int id ;		//标识已储存过的字符串,防止重复计算。
	Trie *next[26];
};

//建树
void build(Trie *t , char name[] , int id)
{
	int len =strlen(name) ;
	for(int i = 0 ; i < len; ++i)
	{
		if(t->next[name[i]-'a'] == NULL)
		{
			Trie *temp = (Trie*)malloc(sizeof(Trie)) ;
			temp->count=1;
			temp->id = id ;
			for(int j = 0 ; j < 26 ; ++j)
			{
				temp->next[j] = NULL ;
			}
			t->next[name[i]-'a'] = temp ;
			t = temp ;
		}
		else
		{
			t = t->next[name[i]-'a'] ;
			if(id != t->id)
				t->count ++;
			t->id = id ;
		}

	}
}
int count = 0 ;
bool flag[MAX] ;
//查询
void query(Trie *t , char str[])
{
	int len = strlen(str) , i ;
	for(i = 0 ; i < len ; ++i)
	{
		if(t->next[str[i]-'a'] != NULL)
		{
			t = t->next[str[i]-'a'] ;
		}
		else
		{
			break ;
		}
	}
	if( i == len )
	{
		if(!flag[t->id])
		{
			count += t->count ;
			flag[t->id] = true ;
		}
	}
}

int main()
{
	int n ;
	scanf("%d",&n);
	Trie *t=(Trie *)malloc(sizeof(Trie));
	for(int i = 0 ; i < 26 ; ++i)
	{
		t->next[i] = NULL ;
	}
	t->count = 0 ;
	for(int i =0 ; i < n ; ++i)
	{
		char name[30];
		scanf("%s",name) ;
		int len = strlen(name) ;
		for(int j = 0 ; j < len ; ++j)
		{
			build(t,name+j,i);
		}
	}
	int q;
	scanf("%d",&q);
	for(int i = 0 ; i < q ; ++i)
	{
		memset(flag,0,sizeof(flag)) ;
		char str[30];
		count = 0 ;
		scanf("%s",str);
		query(t,str) ;
		printf("%d\n",count) ;
	}
	return 0 ;
}

//严格的来说,如果是测试多组测试数据,,应该释放内存,,但是就一组测试数据,释不释放都无所谓啦!下面超时的代码里有释放内存的函数,如果想知道怎么释放,可以参考下面的代码。

下面是第一次超时的代码,,大家可以无视跳过。。

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

struct Trie{
	int count;
	Trie *next[26];
};

void build(Trie *t , char name[])
{
	int len =strlen(name) ;
	for(int i = 0 ; i < len; ++i)
	{
		if(t->next[name[i]-'a'] == NULL)
		{
			Trie *temp = (Trie *)malloc(sizeof(Trie)) ;
			temp->count=1;
			for(int j = 0 ; j < 26 ; ++j)
			{
				temp->next[j] = NULL ;
			}
			t->next[name[i]-'a'] = temp ;
			t = temp ;
		}
		else
		{
			t = t->next[name[i]-'a'] ;
			t->count ++;
		}

	}
}
int count = 0 ;
void query(Trie *t , char str[],int index)
{
	if(index == strlen(str))
	{
		count += t->count ;
		return ;
	}
	for(int i = 0 ; i < 26 ; ++i)
	{
		if(t->next[i] != NULL)
		{
			if(i == str[index]-'a')
			{
				query(t->next[i],str,index+1);
			}
			else
			{
				query(t->next[i],str,0) ;
			}
		}
	}
}

void destroy(Trie *t)
{
	for(int i = 0 ; i < 26 ; ++i)
	{
		if(t->next[i] != NULL)
			destroy(t->next[i]) ;
	}
	free(t);
}

int main()
{
	int n ;
	scanf("%d",&n);
	Trie *t=(Trie *)malloc(sizeof(Trie));
	for(int i = 0 ; i < 26 ; ++i)
	{
		t->next[i] = NULL ;
	}
	t->count = 0 ;
	for(int i =0 ; i < n ; ++i)
	{
		char name[30];
		scanf("%s",name) ;
		build(t,name);
	}
	int q;
	scanf("%d",&q);
	for(int i = 0 ; i < q ; ++i)
	{
		char str[30];
		count = 0 ;
		scanf("%s",str);
		query(t,str,0) ;
		printf("%d\n",count) ;
	}
	destroy(t) ;
	return 0 ;
}

可能这个代码没什么用,就作为给自己的一个警告吧!

下面是正确的代码

时间: 2024-11-05 17:33:27

hdu 2846 Repository 字典树的一种变形的相关文章

hdu 2846 Repository 字典树

// hdu 2846 Repository 字典树 // // 题目大意: // // 有n个字符串,m个待询问的字符串,问这些字符串里面以该询问的 // 字符串为子串的字符串有多少个 // // 解题思路: // // 字典树,将字符串的所有子串插入到字典树中,并设立一个No.标识 // 以免重计数.最后查询就好了 // // 感悟: // // 这题的数据量有点大,虽然p是10000,但是长度是20,单个字符串的 // 最大子串数粗略的估计是 20 * 20 ,所以开的空间也要比较大.开始

HDU 2846 Repository(字典树,标记)

题目 字典树,注意初始化的位置~!!位置放错,永远也到不了终点了org.... 我是用数组模拟的字典树,这就要注意内存开多少了,,要开的不大不小刚刚好真的不容易啊.... 我用了val来标记是否是同一个串分解而来的,保存的是串的编号 num记录数目. //string &replace(iterator first0, iterator last0,const_iterator first, const_iterator last); //把[first0,last0)之间的部分替换成[firs

HDU 2846 Repository (字典树 后缀建树)

Repository Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2932    Accepted Submission(s): 1116 Problem Description When you go shopping, you can search in repository for avalible merchandises

HDU 1247 简单字典树

Hat’s Words Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 7359    Accepted Submission(s): 2661 Problem Description A hat’s word is a word in the dictionary that is the concatenation of exactly

HDU 2846 Repository(字典树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2846 题目:输入个n个词典串,然后输入q个串,对这q个串分别输出每个串都是几个词典串的子串. 思路:因为要包含子串,比如abd,将串abd,bd,d都插入字典树,然后每个节点下统计子树个数,直接查找前缀就可以了.但需要注意dcda这种的,需要插入dcda,cda,da,a,这个时候d下面的子树应该是一个而不是2个,因为dcda和da属于同一个词典串.所以在插入的时候进行处理即可. 代码 #inclu

hdu 1979 DFS + 字典树剪枝

http://acm.hdu.edu.cn/showproblem.php?pid=1979 Fill the blanks Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 373    Accepted Submission(s): 155 Problem Description There is a matrix of 4*4, yo

hdu 1298 T9(字典树+DFS)

题目连接:hdu 1298 T9 题目大意:模拟手机打字的猜想功能,根据概率,每按一个按键,输出可能性最高的串.先给定N个单词,以及频率, 然后是Q次询问,每次询问给定一个按按键的顺序,以1为终止. 解题思路:对单词表建立字典树,每个节点有一个经过的频率,这个频率是根据所有经过该节点的单词频率总和.然后 DFS搜索一遍,将答案保存在ans中. #include <cstdio> #include <cstring> #include <algorithm> using

HDU 1671 (字典树统计是否有前缀)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1671 Problem Description Given a list of phone numbers, determine if it is consistent in the sense that no number is the prefix of another. Let's say the phone catalogue listed these numbers: 1. Emergenc

[HDU] 4825 (01字典树)

Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大.Prometheus 为了让 Zeus 看到人类的伟大,随即同意 Zeus 可以向人类求助.你能证明人类的智慧么? Input 输入包含若干组测试数据,每组测试数据