HDU 3901 Wildcard AC主动机通配符…

http://acm.hdu.edu.cn/showproblem.php?pid=3901

 

题目大意:

两个长度不超过100000的字符串, 一个是带有通配符?和*的模式串,
问能否匹配. 通配符不超过10个.

 

解题思路:首先由'*'字符,将模式串分为若干子串。同时对 首尾
是否 含有'*' 字符进行特判。在匹配文本中 这些若干子串的匹配必须满足 下一段子串 的文本匹配
开始点,为上一段子串 的 末尾处+1 在具体的匹配过程中,将以划分的 子串 ,按照'?' 字符进行进一步的
划分。对得到的 若干小 子串 进行 字典树建树 并采用 AC 自动机 进行匹配搜索 即
设文本串为S, 某一只含?和小写字母的模式串T,
去掉问号后得到若干子串P1, P2, P3, ...Pk,
每个子串结束的下标为L1, L2, L3, ...Lk,
则把Pi丢到AC自动机里面, 开始匹配, 一旦S匹配到j时匹配到
某个Pi的末尾时, 向cnt[j - Li]+1.
最后所有满足cnt[x] == k的x都是S中满足条件的子串开头.
PS: j - Li可能小于0

最后,只有匹配完所有的子串时,才满足条件。

本题 参考 资料  http://www.cnblogs.com/zcwwzdjn/archive/2012/03/10/2389514.html
http://www.cnpetweb.com/a/xinxizhongxin/lanmu9/2011/0827/9300.html
http://nightelf.sinaapp.com/2012/译文:《biosequence-algorithms-spring-2005-lecture-4-set-matching-and-aho-corasick-algorithm》.html

 

 

 //HDU 3901 Wildcard AC主动机通配符匹配
 
 #include
 #include
 #include
 using namespace std;
 #define kind 26
 #define MAX 100010
struct node
{
    int  lis[11];
    int  count;
    node *next[kind];
    node *fail;
};
node pool[MAX],*q[MAX],*index,*root;
char text[MAX],pattern[MAX];
int  cnt[MAX],head,tail,len1,len2,begin;
bool front,last;
node * new_node(){ 
    node *p=index++;    
    p->fail = NULL; 
    p->count=0;
    memset(p->next,0,sizeof(p->next));  
    memset(p->lis,-1,sizeof(p->lis));
    return p; 

void init()
{
    index=pool;
    root=new_node();
}
void insert(char *st,char *ed,int pt)
{
     int ix;
     node *p = root;
     while(st !=ed)
     
         ix=*(st++)-'a';
         if(!p->next[ix])
            p->next[ix]=new_node();
         p=p->next[ix];
     }
     p->lis[p->count++]=pt;  //结尾做标记  
}
void build()
       
     head=0;tail=1;
     q[head]=root;
     node *temp;
     while(head!=tail)
     {
         // next指针,存放搜索匹配失败时 fail指针指向的下一个节点位置
         // 或者 为匹配成功的 下一个字符节点位置
         // 这样,匹配 text时,只须改变 next指针的走向即可 
         temp=q[head++];
         for(int i=0;i< kind ;i ++)
         {
             if(temp->next[i])
             {
                 if(temp==root)temp->next[i]->fail=root;
                 else {// 建立过程中把fail指针中的信息整合
                    temp->next[i]->fail=temp->fail->next[i];      
                    node *tp=temp->fail->next[i];
                    node *tt=temp->next[i];
                    for(int it=0; it < tp->count ; it++)
                       tt->lis[tt->count++]=tp->lis[it];
                                                     
                 q[tail++]=temp->next[i];
             }
             else
             {
                if(temp==root)temp->next[i]=root;
                else temp->next[i]=temp->fail->next[i];
             }
                       
     }
}
bool is_match(int l,int r,bool st,bool ed)//[l,r)
{
   init();
   int pat=0;
   memset(cnt,0,sizeof(cnt));
   for(int i=l;i
      if(pattern[i] == '?')i++;
      else {
         int j=i;
         while(j
         insert(pattern+i ,pattern+j ,j-1-l);
         i=j;
         pat++ ;
      }
   build();
   node *pos = root;
   for(int i=begin;i
      int p =text[i]-'a';
      //搜索匹配,next节点中存放 匹配失败时fail指针的指向节点
      // 或者 为匹配成功时 下一个字符节点位置
      pos = pos->next[p];
      node *tmp=pos;
      for(int it =0 ; it< tmp->count;it++){
         if(i-tmp->lis[it] >=0)
           cnt[i-tmp->lis[it]]++;
      }
   }
   for(int i=begin;i
      if(cnt[i]== pat){
         if(begin==0){
            if(!front && st && i!=0)break;// pattern[0]!='*'
            if(!last  && ed && i+r-l !=len1 )continue;// pattern[len2-1]!='*' 
            begin=i+r-l;
            return true;
         }
         else {
            if(i >= begin){
               if(!last && ed && i+r-l !=len1)continue;
               begin=i+r-l;
               return true;
            }
         }
      }
      return false;
}
int main()
{
    int i,j;
    while(scanf("%s%s",text,pattern)==2)
   
     //   printf("%s\n%s\n",text,pattern);
        len1=strlen(text);
        len2=strlen(pattern);
        if(pattern[0]=='*')front=true;
        else front=false;
        if(pattern[len2-1]=='*')last=true;
        else last=false;
        bool fail=false;
        int split=0;
        int rend=len2;
        begin=0;
        while(rend && pattern[rend-1]=='*')rend--;
        for(i=0;i
        {
           if(pattern[i] == '*')i++;
           else {
             int j=i;
             while(j
             if(!is_match(i,j,split==0,j==rend)){              
                fail=true;
                split++;
                break;
             }
             i=j; 
             split++;
            
        }
        if(split==0)printf("YES\n");
        else if(fail)printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值