[Trie树]模板题

HDU1251: 统计难题

时间限制: 1 Sec  内存限制: 128 MB
提交: 44  解决: 31
[提交][状态][讨论版]

题目描述

Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).

输入

输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串.

注意:本题只有一组测试数据,处理到文件结束.

输出

对于每个提问,给出以该字符串为前缀的单词的数量.

样例输入

banana
band
bee
absolute
acm

ba
b
band
abc

样例输出

2
3
1
0

链表空间小的飞起
#include<cstdio>
#include<cstring>
 
struct tr{
    tr *son[26];
    int cnt;
};
tr *root=new tr;
void init(tr *node)
{
    for(int i=0;i<26;i++)
        node->son[i]=NULL;
}
 
void insert(char *s)
{
    tr *cur=root;
    for(int i=0;i<strlen(s);i++)
    {
        int k=s[i]-'a';
        if(cur->son[k]==NULL)
        {
            tr *p=new tr;
            init(p);
            p->cnt=1;
            cur->son[k]=p;
            cur=cur->son[k];
        }
        else
        {
            cur=cur->son[k];
            (cur->cnt)++;
        }
    }
}
 
int search(char *s)
{
    tr *cur=root;
    for(int i=0;i<strlen(s);i++)
    {
        int k=s[i]-'a';//   printf("%c:%d\n",s[i],cur->son[k]);
        if(cur->son[k]==NULL)
            return 0;
        cur=cur->son[k];
         
    }
    return cur->cnt;
}
 
int main()
{
    char s[20];
    init(root);
    while(gets(s),strcmp(s,""))
        insert(s);
 
    while(gets(s)!=NULL)
        printf("%d\n",search(s));
     
    return 0;
}
 

  

POJ2001: Shortest Prefixes

时间限制: 1 Sec  内存限制: 128 MB
提交: 46  解决: 19
[提交][状态][讨论版]

题目描述

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”.

 

题意:给出n个单词(1<=n<=1000),求出每个单词的非公共前缀,如果没有,则输出自己。

输入

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

 

#include<cstdio>
#include<cstring>
using namespace std;
 
struct trie{
    trie *son[26];
    int cnt;
    trie()
    {
        for(int i=0;i<26;i++)
            son[i]=NULL;
        cnt=0;
    }
};
 
trie *root=new trie;
int n=0;
 
void insert(char *s)
{
    trie *cur=root;
    for(int i=0;i<strlen(s);i++)
    {
        int k=s[i]-'a';
        if(cur->son[k]==NULL)
        {
            trie *last=new trie;
            (last->cnt)++;
            cur->son[k]=last;
            cur=last;
        }
        else
        {
            cur=cur->son[k];
            (cur->cnt)++;
        }
    }
}
 
void prefix(char *s)
{
    trie *cur=root;
    for(int i=0;i<strlen(s);i++)
    {
        if(cur->cnt==1) break;
        cur=cur->son[s[i]-'a'];
        putchar(s[i]);
    }
    putchar('\n');
    return;
}
 
int main()
{
    char s[1020][25];
     
    while(scanf("%s",s[n])!=EOF)
    {
//      if(!strcmp(s[n],"eof")) break;
        insert(s[n]);
        n++;
    }
     
    for(int i=0;i<n;i++)
    {
        printf("%s ",s[i]);
        prefix(s[i]);
    }
     
    return 0;
}

  

2293: [USACO08DEC]洛谷2922 秘密消息Secret Message

时间限制: 1 Sec  内存限制: 128 MB
提交: 8  解决: 6
[提交][状态][讨论版]

题目描述

贝茜正在领导奶牛们逃跑.为了联络,奶牛们互相发送秘密信息.
信息是二进制的,共有M(1≤M≤50000)条.反间谍能力很强的约翰已经部分拦截了这些信息,知道了第i条二进制信息的前bi(l≤bi≤10000)位.他同时知道,奶牛使用N(1≤N≤50000)条密码.但是,他仅仅了解第J条密码的前cj(1≤cj≤10000)位.
对于每条密码J,他想知道有多少截得的信息能够和它匹配.也就是说,有多少信息和这条密码有着相同的前缀.当然,这个前缀长度必须等于密码和那条信息长度的较小者.
在输入文件中,位的总数(即∑Bi+∑Ci)不会超过500000.

输入

第1行输入N和M,之后N行描述秘密信息,之后M行描述密码.每行先输入一个整数表示信息或密码的长度,之后输入这个信息或密码.所有数字之间都用空格隔开.

输出

共M行,输出每条密码的匹配信息数.

样例输入

4 5
3 0 1 0
1 1
3 1 0 0
3 1 1 0
1 0
1 1
2 0 1
5 0 1 0 0 1
2 1 1

样例输出

1
3
1
1
2

提示

 

0 matches only 010: 1 match 1 matches 1, 100, and 110: 3 matches 01 matches only 010: 1 match 01001 matches 010: 1 match 11 matches 1 and 110: 2 matches

 

#include<cstdio>
#include<cstring>
using namespace std;
struct trie{
    trie *son[2];
    int cnt,end;
    trie()
    {
        cnt=0,end=0;
        for(int i=0;i<2;i++)
            son[i]=NULL;
    }
};
trie *root=new trie;
inline int read()
{
    int p=0,f=1;
    char c=getchar();
     
    while(c<'0'||c>'9')
    {
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        p=p*10+c-'0';
        c=getchar();
    }
    return p*f;
}
 
void insert(char *s)
{
    trie *cur=root;
    for(int i=0;i<strlen(s);i++)
    {
        int k=s[i]-'0';
        if(cur->son[k]==NULL)
        {
            trie *last=new trie;
            (last->cnt)++;
            cur->son[k]=last;
            cur=last;
        }
        else
        {
            cur=cur->son[k];
            (cur->cnt)++;
        }
    }
    (cur->end)++;
}
 
int len(char *s)
{
    int ans=0;
    trie *cur=root;
    for(int i=0;i<strlen(s);i++)
    {
        int k=s[i]-'0';
        if(cur->son[k]==NULL) return ans+(cur->end);
        ans+=cur->end;
        cur=cur->son[k];
    }
    return (cur->cnt)+ans;
}
 
int main()
{
    int n,m;
    n=read();m=read();
     
    for(int i=1;i<=n;i++)
    {
        char s[10001];
        memset(s,0,sizeof(s));
        int l=read();
        for(int j=0;j<l;j++)
            s[j]='0'+read();
        insert(s);
    }
     
    for(int i=1;i<=m;i++)
    {
        char check[10001];
        memset(check,0,sizeof(check));
        int l=read();
        for(int j=0;j<l;j++)
            check[j]='0'+read();
        printf("%d\n",len(check));
    }
     
    return 0;
}

  

 

转载于:https://www.cnblogs.com/Yeaaa/p/7072706.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值