首页 > 代码库 > HDU 3901 Wildcard

HDU 3901 Wildcard

题目:Wildcard

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

题意:给一个原串(只含小写字母)和一个模式串(含小写字母、?、* ,*号可替换为0到无穷个任意字母,?可替换为一个任意字母),问两个字符串是否匹配。

思路:

  这是经典题吧。。。

  AC自动机。(网上大多代码是错的,用普通kmp是不行的,不知道修改过后可不可以)。

  HDU已经加强数据了,可我前一个代码abcd ?显示是YES居然还过了,看来数据还是有点弱啊。

  *号的处理是很容易的,只需要把模式串以*号为分界分解开来,然后除了最后一段,其他尽量匹配靠前的原串子串就差不多了,比如ab*cd*ef*gh,那么原串必须以ab开头、gh结尾、然后找到最前的cd、再找到ef,如果互相不重叠就OK。

  比较难的是?的处理了,*分解开模式串分别处理。现在,根据?分解,将分解后的字符串(不含?号了)构建AC自动机。

  比如串A:abcd?abc?cd?abcd,构建AC自动机,然后在结束点记录他在串A中的位置。

  技术分享红色为根,黄色为每一个结束点,这里的fail指针与普通AC自动机相同

  现在我们创建一个数组cnt,对应原串的每一位,让原串在自动机上跑,如果遇到黄点cnt[当前位置-记录的值+1]++,比如遇到abcd,那说明原串当前位置前四位一定是abcd,满足这一段,而如果有某一个cnt值等于4,就说明他满足了所有段,那么他可以作为串A匹配的起点,a b c d _ a b c _ c d _ a b c d,只有上面这种情况才会使第一个a的cnt值为4,而cnt等于4,当前位就是该次匹配满足的最前位置了。

  上一段理解后,题目就可以得解了,注意细节就是了。

AC代码:

  1 #include<stdio.h>  2 #include<string.h>  3 #include<stdlib.h>  4 #include<math.h>  5 #include<set>  6 #include<map>  7 #include<list>  8 #include<stack>  9 #include<queue> 10 #include<vector> 11 #include<string> 12 #include<iostream> 13 #include<algorithm> 14 using namespace std; 15 #define lson rt<<1 16 #define rson rt<<1|1 17 #define N 100010 18 #define M 26 19 #define Mod 1000000007 20 #define LL long long 21 #define INF 0x7fffffff 22 #define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;i++) 23 #define For(i,f_start,f_end) for(int i=f_start;i<f_end;i++) 24 #define REP(i,f_end,f_start) for(int i=f_end;i>=f_start;i--) 25 #define Rep(i,f_end,f_start) for(int i=f_end;i>f_start;i--) 26 #define MT(x,i) memset(x,i,sizeof(x)) 27 #define gcd(x,y) __gcd(x,y) 28 const double PI = acos(-1); 29  30 struct Node 31 { 32   vector<int> d; 33   int fail; 34   int next[M]; 35 }v[N]; 36 int vNum; 37  38 void Init() 39 { 40   v[0].fail = -1; 41   FOR(i,0,25){ 42     v[0].next[i]=-1; 43   } 44   vNum=1; 45 } 46  47 int create() 48 { 49   v[vNum].d.clear(); 50   v[vNum].fail=-1; 51   for(int i=0;i<M;i++) v[vNum].next[i]=-1; 52   return vNum++; 53 } 54  55 int getPos(char c) 56 { 57   return c-a; 58 } 59  60 int add(char *s) 61 { 62   int i,ret=0,p=0; 63   for(i=0;s[i];i++){ 64     if(s[i]==?){ 65       if(p!=0){ 66         ret++; 67         v[p].d.push_back(i); 68         p=0; 69       } 70     } 71     int pos = getPos(s[i]); 72     if(v[p].next[pos]==-1) v[p].next[pos]=create(); 73     p = v[p].next[pos]; 74   } 75   if(p!=0){ 76     ret++; 77     v[p].d.push_back(i); 78   } 79   return ret; 80 } 81  82 queue<int> q; 83 void makeFail() 84 { 85   q.push(0); 86   while(q.size()) 87   { 88     int p=q.front(); 89     q.pop(); 90     for(int i=0;i<M;i++) 91     { 92       if(v[p].next[i]!=-1) 93       { 94         int t=v[p].fail; 95         while(1) 96         { 97           if(t == -1)  // p 已经是根了 98           { 99             v[v[p].next[i] ].fail = 0;100             break;101           }102           else if(v[t].next[i] != -1)103           {104             v[v[p].next[i] ].fail = v[t].next[i];105             break;106           }107           else t=v[t].fail;108         }109         if(t!=-1){110           for(int j=0;j<v[t].d.size();j++){111             v[p].d.push_back(v[t].d[j]);112           }113         }114         q.push(v[p].next[i]);115       }116     }117   }118 }119 120 int cnt[N];121 int match(char *s,char *s1)122 {123   Init();124   int duan = add(s1);125   if(duan==0) return 0;126 127   makeFail();128 129   //printf("%s %s %d\n",s,s1,duan);130 131   memset(cnt,0,sizeof(cnt));132   int i,p=0;133   for(i=0;s[i];i++){134     int pos = getPos(s[i]);135     if(p==-1){136       p=0;137       continue;138     }139     if(v[p].next[pos]==-1){140       p = v[p].fail;141       i--;142       continue;143     }144     p = v[p].next[pos];145     for(int j=0;j<v[p].d.size();j++){146       cnt[i-v[p].d[j]+1]++;147       if(cnt[i-v[p].d[j]+1]==duan) return i-v[p].d[j]+1;148     }149   }150   return -1;151 }152 153 char s[N],s1[N],s2[N];154 bool solve(char *s,char *s1)155 {156   int ls=strlen(s),ps=0;157   int i,len=0,flag=0;158   for(i=0;s1[i];i++){159     if(s1[i]==*){160       if(len!=0){161         s2[len]=0;162         int qi = match(s+ps,s2);163         if(qi==-1) return false;164         if(flag==0 && qi!=0) return false;165         ps += qi + len;166         if(ps>ls) return false;167         len = 0;168       }169       flag=1;170     }171     else s2[len++]=s1[i];172   }173   if(len!=0){174     len--;175     for(i=ls-1;i>=ps && len>=0;i--){176       if(s2[len]!=? && s2[len]!=s[i]) return false;177       len--;178     }179     if(i>=ps && flag==0 || len>=0) return false;180   }181   return true;182 }183 184 int main()185 {186   while(scanf("%s%s",s,s1)!=EOF)187   {188     printf("%s\n",solve(s,s1)?"YES":"NO");189   }190   return 0;191 }

 

HDU 3901 Wildcard