poj2001 Shortest Prefixes

照例先上题目:

2:Shortest Prefixes
查看 提交 统计 提问
总时间限制: 1000ms 内存限制: 65536kB
描述
A prefix of a string is a substring starting at the beginning of the given string. The prefixes of "carbon" are: "c", "ca", "car", "carb", "carbo", and "carbon". Note that the empty string is not considered a prefix in this problem, but every non-empty string is considered to be a prefix of itself. In everyday language, we tend to abbreviate words by prefixes. For example, "carbohydrate" is commonly abbreviated by "carb". In this problem, given a set of words, you will find for each word the shortest prefix that uniquely identifies the word it represents.

In the sample input below, "carbohydrate" can be abbreviated to "carboh", but it cannot be abbreviated to "carbo" (or anything shorter) because there are other words in the list that begin with "carbo".

An exact match will override a prefix match. For example, the prefix "car" matches the given word "car" exactly. Therefore, it is understood without ambiguity that "car" is an abbreviation for "car" , not for "carriage" or any of the other words in the list that begins with "car".
输入
The input contains at least two, but no more than 1000 lines. Each line contains one word consisting of 1 to 20 lower case letters.
输出
The output contains the same number of lines as the input. Each line of the output contains the word from the corresponding line of the input, followed by one blank space, and the shortest prefix that uniquely (without ambiguity) identifies this word.
样例输入
carbohydrate
cart
carburetor
caramel
caribou
carbonic
cartilage
carbon
carriage
carton
car
carbonate
样例输出
carbohydrate carboh
cart cart
carburetor carbu
caramel cara
caribou cari
carbonic carboni
cartilage carti
carbon carbon
carriage carr
carton carto
car car
carbonate carbona
来源
Rocky Mountain 2004


直白的字典树。先根据输入建立trie,从每一个字符串S结束结点E开始,向树根搜索。

  1. 如果E的任一儿子结点不为空,说明S是其他字符串的前缀,为不出现歧义,只能输出S本身。
  2. 否则,从E开始向树根搜索,若遇到(1)结束结点或(2)分叉结点P,则前缀应输出至P的下一个结点。
实现方面:
  1. trie node结构体中添加指向父亲结点的指针。
  2. 用map<string, trie*>储存字符串string的结束结点。

代码清单:
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <map>
#include <vector>
using namespace std;

#define BRANCH 26
#define MAXLEN 25

typedef struct _trie
{
	bool isEnd;
	struct _trie *father;
	struct _trie *branch[BRANCH];
} trie;

map<string, trie*> str2trie;
vector<string> strvec;

void insert(trie *root, char entry[])
{
	trie *current=root;
	int len=strlen(entry);
	int idx;

	for (int i=0; i<len; ++i)
	{
		idx = entry[i]-'a';

		if (current->branch[idx] == NULL)
		{
			current->branch[idx] = new trie;	//新建儿子
			
			current->branch[idx]->isEnd = false;
			for (int j=0; j<BRANCH; ++j)
			{
				current->branch[idx]->branch[j] = NULL;
			}
			current->branch[idx]->father = current;	//设置儿子的父亲结点
		}

		current = current->branch[idx];
	}

	current->isEnd = true;	//标记字符串的结尾

	str2trie[entry]=current;	//current是entry在trie中的结束结点,存入map容器,便于将来查找

	strvec.push_back(entry);
}

void destroy_trie(trie *root)
{
	for (int i=0; i<BRANCH; ++i)
	{
		if (root->branch[i] != NULL)
		{
			destroy_trie(root->branch[i]);
		}
	}

	delete root;
	root=NULL;
}

int numPrefix(trie *node)	//当前字符串是多少个其它字符串的前缀
{
	int count=0;
	for (int i=0; i<BRANCH; ++i)
	{
		if(node->branch[i] != NULL)
			++count;
	}
	return count;
}

void prefix_out()
{
	int dump_suffix, splitpos;
	string tmp_str;
	trie *lastNode, *tmp_last;

	for (int i=0; i<strvec.size(); ++i)
	{
		tmp_str = strvec[i];
		lastNode = str2trie[tmp_str];

		printf("%s ", tmp_str.c_str());

		if(numPrefix(lastNode) == 0)	//不是别的字符串的前缀:向树根查找,遇到1.分叉结点2.isEnd==true的结点,break。则应该输出到此结点的下一个结点(包括)。
		{
			tmp_last=lastNode->father;
			dump_suffix=0;

			while ((tmp_last->isEnd==false) && (numPrefix(tmp_last)==1))
			{
				++dump_suffix;
				tmp_last = tmp_last->father;
			}

			splitpos=strlen(tmp_str.c_str())-dump_suffix;
			tmp_str[splitpos]=0;
		}

		printf("%s\n", tmp_str.c_str());
	}
}

int main()
{
	//freopen("D:\\in.txt", "r", stdin);
	//freopen("D:\\out.txt", "w", stdout);

	char entry[MAXLEN];
	int cursor=0;
	char c;

	trie *root=new trie;
	root->isEnd=false;
	root->father=NULL;
	for (int i=0; i<BRANCH; ++i)
	{
		root->branch[i]=NULL;
	}

	while ((c=getchar()) != EOF)
	{
		if (c != '\n')
		{
			entry[cursor++]=c;
		}
		else
		{
			entry[cursor]=0;

			insert(root, entry);

			cursor=0;
		}
	}

	prefix_out();

	destroy_trie(root);

	return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值