poj3630Phone List用trie树实现

题目:
判断有没有两个电话号码能构成前缀关系
分析:
动态构树果然是Time limitted,只能是用静态构树或者直接安字典序排完序后比较相邻两个是否
能构成前缀关系。。。下面简单说说动态构树吧(应该是对的。。)

下面这个程序因为判了time limitted,应该是对的。。。
#include <iostream>
#include <cstdio>
using namespace std;
struct trie
{ //定义字典树
bool end;
bool id;
trie *p[10];//一共十位数字
trie()
{
end = false;//判断此处到根处有没有单词,有返回true
id = false;//判断是否已有单词在用过从此处回到根的这些号码
for(int i=0;i<10;i++)//开始时没有号码,置NULL
p[i] = NULL;
}
}root;

bool make_tree(struct trie *r,char *s)
{ //动态构树函数
for(int i=0;s[i];i++)
{
if(r->p[s[i]-'0']==NULL)//如果此前没有用过此处的号码,即没有前缀关系
r->p[s[i]-'0'] = new trie();
else if(r->end) //如果这个位置已有号码且该号码在此处结尾,返回false
return false;
r->id = true;//标记此处已经有了号码走过
r = r->p[s[i]-'0'];
if(r->end) //如果这个位置已有号码且该号码在此处结尾,返回false
return false;
}
if(r->id==1||r->end)//此处已有号码在此结尾或者当前号码是别人的前缀
return false;
r->id = true;//标记此处已经有了号码走过
r->end = true;//标记此处已经有了号码在此结尾
return true;
}

int main()
{
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
int t,n;
char s[12];
cin>>t;
while(t--)
{
struct trie qq;
int flag = 0;//标记有没有找到有前缀关系
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",s);
if(!flag&&!make_tree(&qq,s))
flag = 1;
}
if(flag)
printf("NO\n");
else
printf("YES\n");
}
return 0;
}

法1:
可以直接用快排函数排完序后比较前后两个是否构成前缀关系

#include <iostream>
#include <algorithm>
#include <string>
#include <cstdio>
using namespace std;
#define X 10005
string s[X];
int cmp(string s1,string s2)//快排内部比较函数
{
return s1<s2;
}
int main()
{
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
cin>>s[i];
sort(s,s+n,cmp);//直接排序
bool flag = 0;
int i,j;
for(i=0;i<n-1;i++)
{
int len = s[i].size();
for(j=0;j<len;j++)
if(s[i][j]!=s[i+1][j])//如果遇到不等时,即不能构成前缀关系
break;
if(j==len)//表示可以构成前缀关系
{
flag = true;
break;
}
}
if(flag)
printf("NO\n");
else
printf("YES\n");
}
}

静态字典的方法:

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cstdlib>

using namespace std;

#define MAXN 60002

int sum;

struct node      //相当于静态的trie树

{

       int next[11];

}tree[MAXN];

struct phone    //因为要进行二维字符数组的排序,所以要用结构体对输入的电话号码进行储存

{

       char in[11];

}phone[MAXN];

int cmp(const void *a,const void *b)//此算法一定得要从长的字符串开始先插入

{

       struct phone *c = (struct phone *)a;

       struct phone *d = (struct phone *)b;

       return strlen(d->in)-strlen(c->in);

}

bool insert(char *ch)//插入字典

{

       int c,num = 0;

       bool flag = false;

       for(int i=0;ch[i];i++)

       {

              c = ch[i]-'0';

              if(tree[num].next[c]==0) //当目前的位置是空时,说明没有这个号码的前缀

              {

                     flag = true;     //可以置标志为真

                     tree[num].next[c] = ++sum;

                     num = sum;           //指针移动

              }

              else

                     num = tree[num].next[c];

       }

       return flag;     //返回标志

}

int main()

{

       freopen("sum.in","r",stdin);

       freopen("sum.out","w",stdout);

       int t,n;

       cin>>t;

       while(t--)

       {

              memset(tree,0,sizeof(tree));

              bool flag = true;

              scanf("%d",&n);

              for(int i=0;i<n;i++)

                     scanf("%s",phone[i].in);

              qsort(phone,n,sizeof(phone[0]),cmp);

              sum = 0;

              for(int i=0;i<n&&flag;i++)   //i小于n且当前还没有前缀关系,继续插入

                     if(!insert(phone[i].in))//如果有前缀关系的话

                            flag = false;

              if(flag)

                     printf("YES\n");

              else

                     printf("NO\n");

       }

       return 0;

}

 

 

 

编辑器加载中...

转载于:https://www.cnblogs.com/yejinru/archive/2012/02/29/2374679.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值