# 【原】 POJ 3630 Phone List Trie树 解题报告

http://poj.org/problem?id=3630

1、假设91123已经在Trie中，现在要将911插入。假设此时在插最后一个字符1，这时需要判断该1是否也在Trie中，
如果在则证明911是某个字符串的前缀，返回false。如果不在则将其插入。
2、假设911已经在Trie中，现在要将91123插入。插入到第二个1时，因为1已经在Trie中，所以判断是不是有以该1为结尾的字符串。如果有则证明存在一个字符串时91123的前缀，返回false.

Description

Given a list of phone numbers, determine if it is consistent in the sense that no number is the prefix of another. Let's say the phone catalogue listed these numbers:

• Emergency 911
• Alice 97 625 999
• Bob 91 12 54 26

In this case, it's not possible to call Bob, because the central would direct your call to the emergency line as soon as you had dialled the first three digits of Bob's phone number. So this list would not be consistent.

Input

The first line of input gives a single integer, 1 ≤ t ≤ 40, the number of test cases. Each test case starts with n, the number of phone numbers, on a separate line, 1 ≤ n ≤ 10000. Then follows n lines with one unique phone number on each line. A phone number is a sequence of at most ten digits.

Output

For each test case, output "YES" if the list is consistent, or "NO" otherwise.

Sample Input

2

3

911

97625999

91125426

5

113

12340

123440

12345

98346

Sample Output

NO

YES

   1: #include <iostream>
   2: #include <stdio.h>
   3:
   4: using namespace std ;
   5:
   6: struct Node
   7: {
   8:     Node():isStr(false){ memset(son, NULL, sizeof(son) ); }
   9:     bool isStr ;    //为true证明有以该节点为尾的字符串
  10:     Node* son[10] ; //数字0~9
  11: };
  12:
  13: Node buffer[100010] ;  //***重点!!!估计出大概的节点数后用数组缓存，节省了new的时间
  14: //int bufnum = 1 ;
  15:
  16: class Trie
  17: {
  18: private:
  19:     Node root ;  //***
  20:     int bufnum ; //指示buffer已经用到哪里了
  21: public:
  22:     Trie():root(buffer[0]),bufnum(1){}
  23:     bool InsertAndCheck( char* s ) ;
  24:     //void Clear(){ bufnum=1 ; }
  25: };
  26:
  27: bool Trie::InsertAndCheck(char *s)
  28: {
  29:     Node *p = &root ;  //***
  30:     int len = strlen(s) ;
  31:     int digit, i ;
  32:
  33:     for( i=0 ; i<len ; ++i ) //将字符串逐渐插入到Trie中
  34:     {
  35:         digit = s[i]-'0' ;
  36:         if( i==len-1 && p->son[digit]!=NULL ) //特殊情况：要插入的词是已有词前缀的情况。已有91123，插911
  37:             return false ;                    //如果将所有词按长短排序则不需要这步。这步是可以边插边查的关键！！！
  38:
  39:         if( p->son[digit] == NULL )   //如果该字符没出现，则插入，这里用buffer代替new
  40:         {
  41:             p->son[digit] = &buffer[bufnum] ;
  42:             buffer[bufnum].isStr = false ;
  43:             memset( buffer[bufnum].son, NULL, sizeof(buffer[bufnum].son) ) ;
  44:             ++bufnum ;
  45:         }
  46:         else  //该字符已在Trie中
  47:         {
  48:             if( p->son[digit]->isStr == true )  //判断是否有以此字符为结尾的字符串
  49:                 return false ;                  //如果有则已有词是插入词的前缀
  50:         }
  51:         p = p->son[digit] ;  //p指向下一层
  52:     }
  53:
  54:     p->isStr = true ;  //已插入一个单词
  55:     return true ;
  56: }
  57:
  58: void run3630()
  59: {
  60:     int num, n, i ;
  61:     char s[11] ;
  62:     bool flag ;
  63:
  64:     scanf( "%d", &num ) ;
  65:     while( num-- )
  66:     {
  67:         Trie trie ;
  68:         //trie.Clear() ;
  69:         flag = true ;
  70:         scanf( "%d", &n ) ;
  71:         while( n-- )
  72:         {
  73:             scanf( "%s", s ) ;
  74:             flag = trie.InsertAndCheck( s ) ;
  75:             if( !flag )
  76:                 break ;
  77:         }
  78:         while( n-- > 0 )  //如果在插入的过程中得到flag=false，那么后面的输入就没必要在插入并判断，因此break出来
  79:             scanf( "%d", s ) ;  //之后再将其余的输入过掉
  80:
  81:         if( flag )
  82:             printf( "YES\n" ) ;
  83:         else
  84:             printf( "NO\n" ) ;
  85:     }
  86: }
  87:
  88: //************
  89:
  90: char ss[10010][11] ;
  91:
  92: int cmp( const void* a, const void* b )  //一定返回int，不能是bool
  93: {
  94:     return strcmp( (char*)a, (char*)b ) ;
  95: }
  96:
  97: void run3630_1( )
  98: {
  99:     int num, n, i, j, k, len1, len2 ;
 100:     bool flag ;
 101:
 102:     scanf( "%d", &num ) ;
 103:     while( num-- )
 104:     {
 105:         flag = true ;
 106:         scanf( "%d", &n ) ;
 107:         for( i=0 ; i<n ; ++i )
 108:             scanf( "%s", ss[i] ) ;
 109:         qsort( ss, n, sizeof(char)*11, cmp ) ;  //按字符串顺序排序，前缀一定在包含它的字符串之前且紧挨
 110:         for( i=0 ; i<n-1 ; ++i )
 111:         {
 112:             k = 0 ;
 113:             j = i+1 ;
 114:             len1 = strlen( ss[i] ) ;
 115:             len2 = strlen( ss[j] ) ;
 116:             if( len1 < len2 )
 117:             {
 118:                 while( ss[i][k]!='\0' && ss[i][k]==ss[j][k] )
 119:                     ++k ;
 120:                 if( ss[i][k]=='\0' )  //存在前缀
 121:                 {
 122:                     flag = false ;
 123:                     break ;
 124:                 }
 125:             }
 126:         }
 127:
 128:         if( flag )
 129:             printf( "YES\n" ) ;
 130:         else
 131:             printf( "NO\n" ) ;
 132:     }
 133: }
posted @ 2010-11-08 19:59  Allen Sun  阅读(398)  评论(0编辑  收藏  举报