hdu2896 ac自动机

给定几个模式串,看是否出现在主串中。

用所给的模式串构建AC自动机,然后用主串去匹配。

每个模式串的末尾记录该串的标号,而中间的字符的标号为0即可,最后跑一次AC自动机就行了。

3
aaa
bbb
ccc
2
aaabbbccc
bbaacc
 


Sample Output
web 1: 1 2 3
total: 1

const  int  maxn = 1000008  ;

struct TrieNode{
       TrieNode *fail ;
       TrieNode *next[130] ;
       int id ;
       TrieNode(){
           fail = NULL ;
           id = 0 ;
           for(int i = 0 ; i < 130 ; i++) next[i] = NULL ;
       }
};

void  Insert(TrieNode *root , char *s , int id){
      TrieNode *now = root  ;
      while(*s){
          int k = *s - ' ' ;
          if(now->next[k] == NULL)
               now->next[k] = new TrieNode() ;
          now = now->next[k] ;
          s++ ;
      }
      now->id = id ;
}

TrieNode *que[maxn] ;
void makeAC(TrieNode *root){
     int head = 0 , tail = -1 ;
     que[++tail] = root ;
     while(head <= tail){
          TrieNode *now = que[head++] ;
          for(int i = 0 ; i < 130 ; i++){
              if(now->next[i] != NULL){
                  if(now == root)
                      now->next[i]->fail = root ;
                  else{
                      TrieNode *f = now->fail ;
                      while(f != NULL){
                          if(f->next[i] != NULL){
                              now->next[i]->fail = f->next[i] ;
                              break ;
                          }
                          f = f->fail ;
                      }
                      if(f == NULL)
                          now->next[i]->fail = root ;
                  }
                  que[++tail] = now->next[i] ;
              }
          }
     }
}

int  vis[508] ;
int  ask(TrieNode *root , char *s){
     memset(vis , 0 , sizeof(vis)) ;
     TrieNode *now = root ;
     int sum = 0 , k ;
     while(*s){
          k = *s - ' ' ;
          while(now != root && now->next[k] == NULL)
            now = now->fail ;
          now = now->next[k] ;
          if(now == NULL) now = root ;
          TrieNode *f = now ;
          while(f != root){
               vis[f->id] = 1 ;
               if(f->id > 0) sum++ ;
               f = f->fail ;
          }
          s++ ;
     }
     return sum ;
}


char word[208] ;
char text[10008] ;

int  main(){
     int n , m  , i , j , total  ;
     while(cin>>n){
          TrieNode *root = new TrieNode() ;
          for(i = 1 ; i <= n ; i++){
              scanf("%s" , word) ;
              Insert(root , word , i) ;
          }
          total = 0 ;
          makeAC(root) ;
          cin>>m ;
          for(i = 1 ; i <= m ; i++){
               scanf("%s" , text) ;
               if(ask(root , text) > 0){
                   total++ ;
                   printf("web %d:" , i) ;
                   for(j = 1 ; j <= n ; j++){
                      if(vis[j]) printf(" %d" , j) ;
                   }
                   puts("") ;
               }
          }
          printf("total: %d\n" ,total) ;
     }
     return 0 ;
}


/*AC-------------*/
const  int maxn = 500*208 ;
const  int kind = 128 ;
int    next[maxn][kind] ;
int    fail[maxn] ;
int    id[maxn]   ;

struct  AC{
        int  root , n ;
        int  newnode(){
             id[n] = 0 ;
             for(int i = 0 ; i < kind ; i++) next[n][i] = -1 ;
             return n++ ;
        }
        void  Init(){
              n = 0 ;
              root = newnode() ;
        }
        void  Insert(char *s , int idx){
              int now = root  , k ;
              while(*s){
                   k = *s - ' ' ;
                   if(next[now][k] == -1)
                       next[now][k] = newnode() ;
                   now = next[now][k] ;
                   s++ ;
              }
              id[now] = idx  ;
        }
        void  makeAc(){
              queue<int> q ;
              fail[root] = root ;
              int now , i ;
              for(i = 0 ; i < kind ; i++){
                   if(next[root][i] == -1)
                       next[root][i] = root ;
                   else{
                       fail[next[root][i]] =  root ;
                       q.push(next[root][i]) ;
                   }
              }
              while(! q.empty()){
                   now = q.front() ; q.pop() ;
                   for(i = 0 ; i < kind ; i++){
                       if(next[now][i] == -1)
                           next[now][i] = next[fail[now]][i] ;
                       else{
                           fail[next[now][i]] = next[fail[now]][i] ;
                           q.push(next[now][i]) ;
                       }
                   }
              }
        }
        bool vis[508] ;
        int  ask(char *s , int m , int idx){
             memset(vis , 0 , sizeof(vis)) ;
             int now = root , k  ;
             while(*s){
                  k = *s - ' ' ;
                  now = next[now][k] ;
                  int t = now  ;
                  while(t != root){
                       vis[id[t]] = 1 ;
                       t = fail[t] ;
                  }
                  s++ ;
             }
             vector<int> lis ;  lis.clear() ;
             for(int i = 1 ; i <= m ; i++){
                  if(vis[i]) lis.push_back(i) ;
             }
             if(lis.size() == 0) return 0 ;
             else{
                 printf("web %d:" , idx) ;
                 for(int i = 0 ; i < lis.size() ; i++) printf(" %d" , lis[i]) ;
                 puts("") ;
                 return 1 ;
             }
        }
}ac ;
/*EndAc---------------*/

char  word[208] ;
char  text[10008] ;

int   main(){
      int t , n  , i  , sum  , m ;
      while(cin>>n){
           ac.Init() ;
           for(i = 1 ; i <= n ; i++){
                scanf("%s" , word) ;
                ac.Insert(word , i) ;
           }
           ac.makeAc() ;
           sum = 0 ;
           cin>>m ;
           for(i = 1 ; i <= m ; i++){
                scanf("%s" , text) ;
                sum += ac.ask(text , n , i) ;
           }
           printf("total: %d\n" , sum) ;
      }
      return 0 ;
}






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值