题目:http://poj.org/problem?id=2001
题意:
至少2组字符串,对于每个字符串,找出能识别它的最短前缀,如:abbdef,abcdef。“ab”它们为公共前缀,无法识别,所以对应最短识别前缀为:abb、abc
分析:
建立一棵节Trie树,节点存放单个字母,由根节点到子叶的一条路径为,出现过的单词。加入单词时候,各节点数中值+1,表示该前缀共有次数,最后找到第一个值为1个前缀,即可表示最短识别前缀
代码:
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <string>
#include <math.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
using namespace std;
#define MAX 1000+10
#define MIN -1e+10
#define INF 0x7f7f7f7f
int t, n, m;
struct Trie
{
int id; // 该前缀(由当前字母到根节点的路径)出现次数
Trie *child[26]; // 下一字母节点
Trie()
{
memset(child, 0, sizeof(child));
id = 0;
}
} root;
void insert(char str[]) // 插入一个单词,更新维护一条路径
{
Trie *x = &root;
for(int i = 0; str[i]; i++) // 逐个插入
{
if(x->child[str[i]-'a'] == NULL) // 该前缀未出现过
{
Trie *p = new Trie;
x->child[str[i]-'a'] = p;
x = p;
}
else x = x->child[str[i]-'a']; // 该前缀已经存在
x->id++; // 该前缀出现次数+1
}
}
void output(char str[]) // 输出一个单词的最短识别前缀
{
Trie *x = &root;
char str1[30], len = 0;
for(int i = 0; str[i]; i++)
{
x = x->child[str[i]-'a']; // 向下查找前缀
str1[len++] = str[i];
if(x->id == 1) // 找到第一个出现次数为1的前缀,直接输出
break;
}
str1[len] = '\0';
printf("%s %s\n",str, str1);
}
int main()
{
int i, j, k;
freopen("a.txt", "r", stdin);
char str[MAX][30];
for(n = 0; ~scanf("%s", str[n]); n++)
{
insert(str[n]);
}
for(i = 0; i<n; i++)
{
output(str[i]);
}
return 0;
}