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;
}