考查:AC自动机
提交:1次AC 1594MS
第二道AC自动机的题目,对AC自动机fail指针的构造和含义以及查找有了一点新的认识,写了一些在注释中。代码参考了http://hi.baidu.com/aconly/blog/item/fa6dc7344fd6901890ef3941.html
另外,发现用C++提交的时间是1547MS,GCC是1500MS,G++是1594MS,好像GCC会快点,不过也有可能是服务器的原因~
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct _n { int id; struct _n *fail; struct _n *next[26]; }node; int L,C,W; char puzzle[1001][1001]; node *root; node *queue[100001]; int ans[1001][3],len[1001]; int dir[8][2]={{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}}; void insert(char *key,int id) { int i; node *p=root; for(i=0;key[i];i++) { if(!p->next[key[i]-'A']) { p->next[key[i]-'A']=(node*)malloc(sizeof(node)); memset(p->next[key[i]-'A'],0,sizeof(node)); } p=p->next[key[i]-'A']; } p->id=id; } void ac_auto() { int i,front,back; node *tmp,*p; front=back=0; queue[back++]=root; while(front!=back) { tmp=queue[front++]; for(i=0;i<26;i++) { if(tmp->next[i]==NULL) continue; if(tmp==root) { tmp->next[i]->fail=root; //队列中放的是当前节点的孩子节点 //root孩子节点的fail都指向root queue[back++]=tmp->next[i]; continue; } //沿父指针的失败节点查找和当前节点字符相同的节点 //和当前字符相同表示为p->next[i]!=NULL for(p=tmp->fail;p!=NULL;p=p->fail) { if(p->next[i]!=NULL) { tmp->next[i]->fail=p->next[i]; break; } } if(p==NULL) tmp->next[i]->fail=root; queue[back++]=tmp->next[i]; } } } void match(int x,int y,int k) { int i,j,idx,id; node *tmp,*p=root; for(i=x,j=y;i>=0&&i<L&&j>=0&&j<C;i+=dir[k][0],j+=dir[k][1]) { idx=puzzle[i][j]-'A'; while(p->next[idx]==NULL&&p!=root) p=p->fail; p=p->next[idx]; if(p==NULL) p=root; //查找时通过标记节点中的id来标识访问过 //统计 for(tmp=p;tmp!=NULL&&tmp->id!=-1;tmp=tmp->fail) { id=tmp->id; ans[id][0]=i-len[id]*dir[k][0]; ans[id][1]=j-len[id]*dir[k][1]; ans[id][2]=k; tmp->id=-1;//标记为已访问过 } } } int main() { int i,j; char key[1001]; root=(node*)malloc(sizeof(node)); memset(root,0,sizeof(node)); scanf("%d%d%d",&L,&C,&W); for(i=0;i<L;i++) scanf("%s",puzzle[i]); for(i=1;i<=W;i++) { scanf("%s",key); len[i]=strlen(key)-1; insert(key,i); } ac_auto(); for(i=0;i<C;i++) for(j=0;j<8;j++) { match(0,i,j); match(L-1,i,j); } for(i=0;i<L;i++) for(j=0;j<8;j++) { match(i,0,j); match(i,C-1,j); } for(i=1;i<=W;i++) printf("%d %d %c/n",ans[i][0],ans[i][1],ans[i][2]+'A'); return 0; }