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 }

 

posted @ 2016-09-30 21:55  hchlqlz  阅读(407)  评论(0编辑  收藏  举报