字典树 poj 2001

不管你看不看,我要坚持写。言而无信可耻,你随便。。。发火

题目链接:http://poj.org/problem?id=2001

题目大意:给你很多个字符串,让你找每个字符串的最短前缀,但这么多字符串前缀不能有相同的,要能唯一标识一个字符串,而且前缀长度尽量小。

思路:  一开始我们很容易想到用一大堆string.h里面的各种字符串处理的函数。但这类问题数据量一般很大,一般会超时,而且不好写(我是不会写也不敢那样写抓狂)。如果以前知道字典树是干嘛的话,很自然就想到字典树问题;

所谓字典树。。。

参考:http://baike.baidu.com/view/2759664.htm   http://www.cnblogs.com/DiaoCow/archive/2010/04/19/1715337.html

没观众,没动力,没心情像前两篇讲dijkstra 和prim算法时那么详细了。。。

看完,理解了字典树了吧?那么,继续。我们可以记录一下每个节点被经过了几次,若nCount = 1,则说明到它当前缀的结尾肯定是唯一,否则不唯一;我猜猜猜:你如果是笨蛋的话,会问:

字符串abcde abcdefg 我让第一个的是a,第二个的是abcdef,这样a的 nCount>1,不行吗?不行,a不能唯一表示。前缀,前缀。。。

学长大神洪帮主说:字典树相当有用,今天才选这个主题。。。。

看代码:有详细注释:

//Accepted	564K	32MS	C++	1187B	
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

struct TrieNode  //c++里的struct 可以有函数的
{
    int nCount; //记录有多少个分支经过该节点
    struct TrieNode *next[26];  //题目中只有小写字母,所以是26,若有大小写则为52。若还有数字,自己用脚趾头想吧
    TrieNode()   //构造函数,就是在你申请一个节点空间时,把节点初始化
    {
        nCount = 0;
        memset(next,0,sizeof(next));
    }
};
char str[1010][30];  //看题目数据
TrieNode *root = NULL; //全局变量 ,尽管祝建华不建议多用,但在acm中,能方便就方便
void MakeTrie(char *s)   //构造字典树
{
    TrieNode * p = root; 
    TrieNode * tmp = NULL ;
    for(size_t i = 0; i < strlen(s); i++)
    {
        if(p->next[ s[i] - 'a'] == NULL)  //相当于一棵有26个儿子的树,当然你用到那个分支,就选那个s[i]-'a'就是这么来的
        {
            tmp = new  TrieNode;     //申请空间,初始化26个分支(memset啊啊啊),nCount置为0
            p->next[ s[i] - 'a'] = tmp; //加到树上  看不懂,就去死吧
        }
        p = p->next[ s[i] - 'a'];   //就像你写p = p->next一样
        p->nCount ++;  //记录有多少分支经过该节点
    }
}
void SearchTrie(char *s)
{
    TrieNode * p = root;
    for(size_t i = 0; i < strlen(s); i++)
    {
        p = p->next[s[i] - 'a']; 
        printf("%c",s[i]);
        if(p->nCount == 1)   //==1就说明该节点只有1个分支经过,就说明以它为结尾的前缀是惟一的,果断跳出
        break;
    }
}
int main()
{
    int num = 0;
    root = new TrieNode;//自动调用构造函数初始化next[i]为NULL

    while(cin >> str[num])
    {
        MakeTrie(str[num]);
        num ++;
    }
    for(int i = 0; i < num; i++)
    {
        printf("%s ",str[i]);
        SearchTrie(str[i]);
        printf("\n");
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值