POJ 1204 Word Puzzles | AC 自动鸡

题目:

给一个字母矩阵和几个模式串,矩阵中的字符串可以有8个方向

输出每个模式串开头在矩阵中出现的坐标和这个串的方向


题解:

我们可以把模式串搞成AC自动机,然后枚举矩阵最外围一层的每个字母,向八个方向进行匹配

代码中danger标记为判断这个节点是不是一个模式串的结尾,

这道题可以直接字符串反向构建AC自动机,匹配到的就是开头(代码是正向)

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define Z 27
#define N 1010
using namespace std;
struct node
{
    int trans[Z],fail,danger;
    void init()
	{
	    memset(trans,0,sizeof(trans));
	    danger=fail=0;
	}
}tr[1000010];
char puzzle[N][N],s[N],dir[10]={'A','B','C','D','E','F','G','H'};
int l,c,w,dx[10]={-1,-1,0,1,1,1,0,-1},dy[10]={0,1,1,1,0,-1,-1,-1};
int fa[N],ansx[N],ansy[N],tot=1,len[N],d[N];

int find(int x)
{
    return fa[x]=fa[x]==x?x:find(fa[x]);
}

void insert(char s[],int id)
{
    int len=strlen(s+1),now=1;
    for (int i=1;i<=len;i++)
    {
	if (tr[now].trans[s[i]-'A']==0)
	    tr[tr[now].trans[s[i]-'A']=++tot].init();
	now=tr[now].trans[s[i]-'A'];
    }
    if (tr[now].danger)
	fa[find(id)]=find(tr[now].danger);
    else
	tr[now].danger=id;
}

void BuildFail()
{
    queue <int> q;
    tr[1].fail=1;
    for (int i=0;i<26;i++)
    {
	if (tr[1].trans[i]==0)
	    tr[1].trans[i]=1;
	else
	{
	    tr[tr[1].trans[i]].fail=1;
	    q.push(tr[1].trans[i]);
	}
    }
    while (!q.empty())
    {
	int u=q.front(),v,w;
	for (int i=0;i<26;i++)
	{
	    v=tr[u].fail;
	    v=tr[v].trans[i],w=tr[u].trans[i];
	    if (w) tr[w].fail=v,q.push(w);
	    else tr[u].trans[i]=v;
	}
	q.pop();
	if (tr[u].danger==0 && tr[tr[u].fail].danger)
	    tr[u].danger=tr[tr[u].fail].danger;
    }
}

void query(int x,int y,int t)
{
    int p=1;
    while (x>0 && y>0 && x<=l && y<=c)
    {
	p=tr[p].trans[puzzle[x][y]-'A'];
	int ap=p;
	while (tr[ap].danger)
	{
	    int k=tr[ap].danger;
	    ansx[k]=x-dx[t]*(len[k]-1);
	    ansy[k]=y-dy[t]*(len[k]-1);
	    d[k]=t;
	    ap=tr[ap].fail;
	}
	x+=dx[t];
	y+=dy[t];
    }
}

int main()
{
    scanf("%d%d%d",&l,&c,&w);
    for (int i=1;i<=l;i++)
	scanf("%s",puzzle[i]+1);
    for (int i=1;i<=w;i++)
    {
	scanf("%s",s+1);
	fa[i]=i;
	len[i]=strlen(s+1);
	insert(s,i);
    }
    BuildFail();
    for (int i=1;i<=l;i++)
	for (int j=0;j<8;j++)
	    query(i,1,j),query(i,c,j);
    for (int i=1;i<=c;i++)
	for (int j=0;j<8;j++)
	    query(1,i,j),query(l,i,j);
    for (int i=1;i<=w;i++)
	printf("%d %d %c
",ansx[i]-1,ansy[i]-1,dir[d[i]]);
    return 0;
}
原文地址:https://www.cnblogs.com/mrsheep/p/7988920.html