POJ - 2001 Shortest Prefixes(字典树重复前缀查询)

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”.
Input
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.
Output
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.
Sample Input
carbohydrate
cart
carburetor
caramel
caribou
carbonic
cartilage
carbon
carriage
carton
car
carbonate
Sample Output
carbohydrate carboh
cart cart
carburetor carbu
caramel cara
caribou cari
carbonic carboni
cartilage carti
carbon carbon
carriage carr
carton carto
car car
carbonate carbona

题意:输入N个单词,输出N个单词本身以及在该单词在字典中不会与其他单词混淆的最短前缀缩写。

字典树的应用,注意题目要求不会做出的单词前缀缩写不至于与其他单词的前缀缩写混淆,那么比如 若3个单词都带有前缀carb,那么三个单词的前缀缩写都不会是carb,而是carboh carbu carboni 除了某些单词本身太短,其整个单词都与其他单词的前缀重复了,如car和carbon,此时输出单词本身。

那么首先建立字典树,除了记录单词结束节点外,还需记录每个节点出现次数。若一些节点多次出现(>=2次),那么说明该节点不能作为前缀缩写,当第一次遇到某个单词的节点出现次数为1时,那么从第一个字母到这个节为止将是该单词的无歧义前缀缩写,至于另一种情况:整个单词都是其他单词的前缀时,就不能判断该单词字母在树中出现次数了,而是只要遇到单词结尾标记即输出整串单词作为缩写。

注意,不能在输出find函数中检查str[i+1]的节点是否为1,只能检查当前位是否为1,否则测试cc时,因为第一个字符直接可以代替cc,但是输出时会将下一个为1的字符同时输出,这样就错了
if(vis[tre[rt][str[i+1]-‘a’]]==1)printf(“%c\n”,str[i+1]); 这样的操作是错误的
代码如下:

#include
#include
int tot,tre[6000][26],vis[6000];///字典树开大点,不然总返回WA都不知道去哪儿找错
char word[1002][23];
int insert(char str[],int rt)
{
    int len=strlen(str);
    for(int i=0; iint x=str[i]-'a';
        if(tre[rt][x]==0)
        {
            tre[rt][x]=++tot;
            memset(tre[tre[rt][x]],0,sizeof(tre[tre[rt][x]]));
        }
        rt=tre[rt][x];
        vis[rt]++;
    }
}
void finds(char str[],int rt)
{
    int len=strlen(str);
    for(int i=0; iint x=str[i]-'a';
        rt=tre[rt][x];
        printf("%c",str[i]);
        if(vis[rt]==1)
        {
            printf("\n");
            return;
        }
        if(i==len-1)
        {
            printf("\n");
            return;
        }
    }
}
int main()
{
    int num=0;
    tot=0;
    int rt=++tot;
    memset(tre[rt],0,sizeof(tre[rt]));
    memset(vis,0,sizeof(vis));
    while(scanf("%s",word[++num])!=EOF) insert(word[num],rt);
    for(int i=1; i<=num; i++)
    {
        printf("%s ",word[i]);
        finds(word[i],rt);
    }
}

你可能感兴趣的:(字典树)