hihocoder 1107 : Shortest Proper Prefix

题目大意

给定N个单词,求满足下列条件的前缀集合S

  • 集合中任意前缀对应的单词数量小于等于5
  • 对于集合中任意前缀pp的扩展前缀不属于该集合

对于第二个条件,举个例子来说:

假设ab对应了5个单词,abc对应了3个单词,abd对应了2个单词。

因为ab对应的单词数量少于等于5,所以ab属于集合S。虽然abcabd对应的单词数量均小于等于5,但由于其为ab的扩展,所以不属于S

解题思路

由于本题需要询问多个单词的公共前缀,很显然的是一道Trie树的题目,关于Trie树的讲解,可以点击这里学习。

首先我们将所有的单词建立成一颗Trie树,举个例子:

hihocoder 1107 : Shortest Proper Prefix_第1张图片

对于树上任意一个节点,表示从根到节点路径构成的前缀,其数字表示该前缀对应的单词数量。

题目中描述的两个条件很容易在该Trie树中判定:

  • 当节点数字小于等于5时,则表示该前缀是一个合法解
  • 当节点为合法解时,以它为根的子树上其他节点都不再计入合法解

在上图中,蓝色节点表示最后属于集合S的前缀。

由此我们可以得到一个简单的算法:

  1. 对构建好的Trie树进行遍历
  2. 若当前节点计数小于等于5,返回1
  3. 若当前结点计数大于5,递归对所有子树进行遍历,并返回统计和

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int n,ans;
char str[1000000];
struct node
{
	struct node *next[26];
	int num;
}Node;

void add(node *root,char *s)
{
	int len = strlen(s);
	node *p = root;
	for(int i = 0; i < len; i++)
	{
		if(p->next[s[i]-'a'] == NULL)
		{
			p->next[s[i]-'a'] = (node *)malloc(sizeof(node));
			for(int j = 0; j < 26; j++)
				p->next[s[i]-'a']->next[j] = NULL;
			p->next[s[i]-'a']->num = 0;
		}
		p = p->next[s[i]-'a'];
		p->num++;
	}
}

void dfs(node *root)
{
	if(root == NULL) return;
	if(root->num <= 5 && root->num != 0)
	{
		ans++;
		return;
	}
	for(int i = 0; i < 26; i++)
	{
		dfs(root->next[i]);
	}
	return;
}

void del(node *root)
{
	if(root == NULL) return;
	for(int i = 0; i < 26; i++)
	{
		del(root->next[i]);
		free(root->next[i]);
	}
}

int main()
{	
	while(scanf("%d",&n)!=EOF)
	{
		node *root = (node *)malloc(sizeof(node));
		for(int i = 0; i < 26; i++)
			root->next[i] = NULL;
		root->num = 0;
		for(int i = 1; i <= n; i++)
		{
			getchar();
			scanf("%s",str);
			add(root,str);
			memset(str,0,sizeof(str));
		}
		ans = 0;
		dfs(root);
		printf("%d\n",ans);
		del(root);
		free(root);
	}
	return 0;
}


你可能感兴趣的:(hihocder)