现在的位置: 首页 > 综合 > 正文

poj-3630 Phone List **

2012年01月27日 ⁄ 综合 ⁄ 共 3767字 ⁄ 字号 评论关闭

  Trie树入门题。不多说了, 先转一个人家的分析和代码, 自己的代码附在后面。

[转]:

方法一:trie

有了上面学习的思考与总结,3630trie树本以为可以水过,可是学习和做题终究是两回事,我很快写出trie树,然后提交,超时了。

后来受discuss提示,我大致计算了一下本题trie树的复杂度,号码个数10000,长度10,树的宽度大概有10000,所以总的节点数大概就有100,000级(10层,每层10000),即要进行十万次new的操作,确实时间耗费很多,估计这样题目的用时要有1秒到2秒左右的样子。

于是为了纯粹的做题,我将new操作省掉,改为提前申请一个buffer空间,就ac了,时间变为125ms了,不过这样确实挺耗空间的,没办法,为了做题只能用空间换时间。



代码如下:

 1#include<iostream>
2using namespace std;
3int cases, count;
4int nodenum;
5
6struct node
7{
8 bool isExist;
9 node * branch[10];
10}Node[100000];
11
12class Trie
13{
14private:
15 node root;
16public:
17 Trie(){root = Node[0];}
18 bool insert(char num[])
19 {
20 node *location = &root;
21 int i = 0;
22 int len = strlen(num);
23 while(num[i])
24 {
25 if(i==len-1 && location->branch[num[i]-'0'] != NULL) //解决没有按照长度排序而存在的问题
26 {
27 return false;
28 }
29 if(location->branch[num[i]-'0']==NULL)//没有建立
30 {
31 location->branch[num[i]-'0'] = &Node[nodenum];
32 Node[nodenum].isExist = false;
33 memset(Node[nodenum].branch,NULL,sizeof(Node[nodenum].branch));
34 nodenum++;
35 }
36 if(location->branch[num[i]-'0']->isExist == true)
37 {
38 return false;
39 }
40 location = location->branch[num[i]-'0'];
41 i++;
42 }
43 location->isExist = true;
44 return true;
45 }
46};
47
48int main()
49{
50 scanf("%d",&cases);
51 while(cases--)
52 {
53 nodenum = 1;
54 bool flag = true;
55 scanf("%d",&count);
56 char tel[11];
57 Trie t;
58 while(count--)
59 {
60 scanf("%s",tel);
61 if(!t.insert(tel))
62 {
63 flag = false;
64 }
65 }
66 if(flag)
67 {
68 printf("YES\n");
69 }
70 else
71 {
72 printf("NO\n");
73 }
74 }
75 return 0;
76}
77

方法二:

    转成数字存储比较,这样的话用long整形就可以,然用除法+取余的方法核对是否是某个数字的前缀,但是这种方法的复杂度显然是O(n^2)呀,所以就不尝试了。

方法三:

受大雄提示,可以使用字符串排序比较来做,因为通过排序,前缀子串肯定是与父串挨着的,嘿嘿,这样做,思路简单、代码量少,易理解啊,所以很快ac,下面分析一下复杂度。
    
理论上使用trie的平均复杂度应该是n*len;其中,len是号码的平均长度,n是号码的个数。使用数组进行字符比较,理论上的复杂度有n*len+logn,排序为logn,然后查询是否存在前缀子串是n*len。所以后者应该时间稍微多一点,提交后果然,耗时188ms

另外值得一提的是使用数组比较的方法有个好处,那就是地址都是连续的,cpu在寻址时会非常快,而用链式结构(即指针),包括使用数组型的trie树则是跳来跳去的,故会有一些开销吧。

呵呵,我所崇拜的排序又一次派上用场了。

代码如下:

1#include<iostream>
2using namespace std;
3
4int cases, count;
5char tel[10005][11];
6int i, j;
7
8int cmp(const void *a, const void *b)
9{
10 return strcmp( (char*)a,(char*)b );
11}
12
13int main()
14{
15 scanf("%d",&cases);
16 while(cases--)
17 {
18 bool flag = true;
19 scanf("%d",&count);
20 for(i = 0; i < count; i++)
21 {
22 scanf("%s",tel[i]);
23 }
24 qsort(tel,count,sizeof(char)*11,cmp);
25 int len1, len2;
26 for(i = 1; i < count; i++)
27 {
28 len1 = strlen(tel[i-1]);
29 len2 = strlen(tel[i]);
30 j = 0;
31 if(len1 <= len2)
32 {
33 while(tel[i-1][j] == tel[i][j] && j < len1)
34 {
35 j++;
36 }
37 if(j == len1)
38 {
39 flag = false;
40 }
41 }
42 if(!flag)
43 {
44 break;
45 }
46 }
47 if(flag)
48 {
49 printf("YES\n");
50 }
51 else
52 {
53 printf("NO\n");
54 }
55 }
56 return 0;
57}
58

[转] : http://www.cnblogs.com/cherish_yimi/archive/2009/10/12/1581795.html

__________________________________________________________________________________________

MyCode :

/*
* test-3.cpp
*
* Created on: 2011-10-6
*
*/
#include <cstdio>
#include <cstring>
using namespace std;

const int maxN = 10000 + 5;
const int maxL = 10 + 3;
const int alphbetNum = 10;

int caseNum, n, nodeNum;
char telNum[maxL];

struct SData{
SData *next[alphbetNum];
int isExist;
};

SData trieTree[100000];
SData *trie;

SData* createTrie(){
SData *tmpTrie = &trieTree[0];
for(int i=0; i<alphbetNum; i++)
tmpTrie->next[i] = NULL;
tmpTrie->isExist = 0;
return tmpTrie;
}

int insert(char *newString){
SData *tmpTrie = trie;
char *nextChar = newString;
while(*nextChar != '\0'){
if(tmpTrie->isExist == 1)
return -1;

//关于这一步可以用负在下面的测试数据说明
if(strlen(nextChar) == 1 && tmpTrie->next[*nextChar - '0'] != NULL)
return -1;

if(tmpTrie->next[*nextChar - '0'] != NULL)
tmpTrie = tmpTrie->next[*nextChar - '0'];
else{
tmpTrie->next[*nextChar - '0'] = &trieTree[++nodeNum];
tmpTrie = tmpTrie->next[*nextChar - '0'];
for(int j=0; j<alphbetNum; j++)
tmpTrie->next[j] = NULL;
tmpTrie->isExist = 0;
}
nextChar++;
}
tmpTrie->isExist = 1;
return 1;
}


int main(){
scanf("%d", &caseNum);
while(caseNum--){
nodeNum = 0;
trie = createTrie();
bool flag = 1;

scanf("%d", &n);

for(int i=0; i<n; i++){
scanf("%s", telNum);

//如果flag=0则后面的不用再插入了
if(flag && insert(telNum) == -1)
flag = 0;
}

if(!flag) printf("NO\n");
else printf("YES\n");



}


return 0;
}

Input:

2
2
1
12
2
12
1


Output:
NO NO

抱歉!评论已关闭.