poj 4052 Hrinity 2012 金华邀请赛 AC自动机 DFA
2012-07-07 16:29
363 查看
/* 题意: 给定一些匹配串和一个模式串,问有多少个匹配串出现在模式串中。、 1.相同的匹配串记为一次 2.如果匹配串s1和s2都出现在模式串中,那么忽略s1 题解: 如果没有条件2,就是很经典的AC自动机题了。 按照经典方法我们可以找出所有出现过的匹配串,记为集合T,然后再这些串中去掉可以作为T中非自身子串的串 */ #include<cstdio> #include<queue> #include<cstring> #include<iostream> #include<cstring> #include<algorithm> using namespace std; typedef __int64 type; char ch[2505][1105]; int vis[3000],n; const int kind=26; //每个节点的子节点的个数上限 struct Node { int key,cnt; struct Node *next[kind],*fail; Node() { key=0; for(int i=0;i<kind;i++) next[i]=0; } }*root; int Index(char c) { return c-'A'; } void insert(char *s,int t)//构造字典树 { int i=0; Node *p=root; while(s[i]) { if(p->next[Index(s[i])]==0) { p->next[Index(s[i])]=new Node(); } p=p->next[Index(s[i])]; i++; } p->key=1;//是字符串结尾记录为 1 p->cnt=t;//记录是第cnt号串的结尾 } void build_fail() { root->fail=root; queue<Node *> q; q.push(root); while(!q.empty()) { Node *t=q.front();q.pop(); Node *p=0; for(int i=0;i<kind;i++) { if(t->next[i]!=0) { if(t==root) t->next[i]->fail = root; else { p=t->fail; //从父节点的失败指针开始 while(p!=root&&p->next[i]==0) p=p->fail;//循环失败指针,一直搜索非根节点有相同索引的节点 if(p->next[i]) { t->next[i]->fail=p->next[i]; } //找到,失败指针指向它 else t->next[i]->fail=root; //无相同索引,失败指针指向根节点 } q.push(t->next[i]); } } } } int bfs(char *s)//去掉s被标记过的字串 { int i=0,sum=0,len=strlen(s); Node *p=root; while(s[i]) { while(p->next[Index(s[i])]==0&&p!=root) { p=p->fail; }//某个非根节点匹配失败,一直循环失败指针直到有某个字典树分支可以匹配 p=(p->next[Index(s[i])]==0)?root:p->next[Index(s[i])];//一直到根也未找到满足条件的分支,则从根开始匹配 Node *t=p; // if(i==len-1)t=t->fail; while(t!=root&&t->key!=-3)//循环失败指针,记录匹配次数 { if(abs(t->key)==1&&vis[t->cnt])//是结尾,并且被标记则去掉标记 { vis[t->cnt]=0; } t->key=-3; t=t->fail; } i++; } } int query1(char *s) { int i=0,sum=0; Node *p=root; while(s[i]) { while(p->next[Index(s[i])]==0&&p!=root) { p=p->fail; }//某个非根节点匹配失败,一直循环失败指针直到有某个字典树分支可以匹配 p=(p->next[Index(s[i])]==0)?root:p->next[Index(s[i])];//一直到根也未找到满足条件的分支,则从根开始匹配 Node *t=p; while(t!=root&&t->key!=-4)//循环失败指针,记录匹配次数 { if(abs(t->key)==1) sum+=1; t->key=-4; t=t->fail; } i++; } return sum; } int query(char *s) { int i=0,sum=0; Node *p=root; //**************************找到所有出现在模式串中的匹配串 while(s[i]) { while(p->next[Index(s[i])]==0&&p!=root) { p=p->fail; }//某个非根节点匹配失败,一直循环失败指针直到有某个字典树分支可以匹配 p=(p->next[Index(s[i])]==0)?root:p->next[Index(s[i])];//一直到根也未找到满足条件的分支,则从根开始匹配 Node *t=p; while(t!=root&&t->key>=0)//循环失败指针,记录匹配次数 { if(t->key==1)//表示t->cnt号出现过,把标记改为-1,现在abs(key)=1表示是结尾 { vis[t->cnt]=1; t->key=-1; } else t->key=-2;//原来是0的改为-2,负数表示已经走过,这样可以节省时间 t=t->fail; } i++; } //************************** for(int i=1;i<=n;i++) if(vis[i]) { bfs(ch[i]);//i号串出现过,去掉i号串所有的字串,包括自身 insert(ch[i],i);//把自身加回来 } sum=query1(s);//再做一次模式串的匹配 return sum; } char str1[5100009],str2[5100009]; int main() { int m,tt,i,j; scanf("%d", &tt); while(tt--) { memset(vis,0,sizeof(vis)); root=new Node(); scanf("%d", &n); for(int t=1;t<=n;t++) { scanf("%s", str1+1); for(i=1, j=1; str1[i]; i++) { if(str1[i]>='A' && str1[i]<='Z') str2[j++] = str1[i]; else { i++; int k = str1[i]-'0';i++; while(str1[i]<'A' || str1[i]>'Z') k = k*10+ str1[i++]-'0'; while(k--) str2[j++] = str1[i]; i++; } } str2[j] = '\0'; strcpy(ch[t],str2+1); insert(str2+1,t); } build_fail(); scanf("%s", str1+1); for(i=1, j=1; str1[i]; i++) { if(str1[i]>='A' && str1[i]<='Z') str2[j++] = str1[i]; else { i++; int k = str1[i]-'0';i++; while(str1[i]<'A' || str1[i]>'Z') k = k*10+ str1[i++]-'0'; while(k--) str2[j++] = str1[i]; i++; } } str2[j] = '\0'; int ans = query(str2+1); printf("%d\n", ans); } return 0; }
相关文章推荐
- POJ 4052 Hrinity (金华邀请赛I题) AC自动机
- POJ 4052 Hrinity [AC自动机]
- POJ 2012金华邀请赛 (持续更新)
- POJ 4052 金华邀请赛I题
- poj 4047 Garden 2012金华邀请赛 线段树
- POJ 4052 金华邀请赛I题
- POJ 4045 Power Station 2012金华邀请赛B题(树形DP)
- Poj 4047 Garden /2012金华邀请赛D题(线段树)
- poj 4047金华邀请赛 D题 (线段树+lazy优化)
- 2012金华邀请赛总结
- 金华邀请赛B题poj 4046(spfa求最短路)
- POJ 4052 Hrinity(AC自动机)
- 2012金华邀请赛解题报告
- POJ 4049 金华赛区邀请赛F题
- 2012金华邀请赛D题(POJ4047 Garden)解题报告
- poj 4047 Garden(线段树,伤!12年金华邀请赛D题)
- poj 4044 Score Sequence(暴力,12年金华邀请赛A题)
- poj 4047 Garden 2012金华赛区 (成段更新+区间最值)
- POJ-4052-ac自动机
- 2012金华邀请赛 Problem D. Garden 线段树题目