poj 1204 Word Puzzles (AC自动机)

题目链接:   poj 1204

题目大意:   给出字典,再给出n个单词

                  找出这些单词在单词表的什么位置,以什么顺序排放(8个方向,A表示正北,顺时针方向依次为B ~ H)

解题思路:   由于字典太大,若以字典的所有单词建立字典树空间复杂度很高

                  建立n个单词的字典树和失败指针

                  对字典的八个方向枚举,枚举每一个起点,根据AC字典树的特性

                  只需要行枚举(第一列和最后一列)和列枚举(第一行和最后一行)

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 1003
struct snode{
    int w,fail;
    int next[26];
}Tree[MAX*500];
struct node{
    int x,y,fx;
}ans[MAX];
int  n,m,Index,listb[MAX*MAX],Fx[8][2]={{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}};
char ch1[MAX*2];
int ch1len[MAX],Map[MAX][MAX];
void Insert(int Star,int Tlen,int k)  //建立字典树
{
    int i,S=Star,child;
    for(i=1;i<=Tlen;i++)
    {
        child=ch1[i-1]-'A';
        if(Tree[S].next[child]==-1)
        {
			if(i==Tlen)
				Tree[Index].w=k;
			Tree[S].next[child]=Index++;
        }
        else if(i==Tlen)
        {
            Tree[Tree[S].next[child]].w=k;
        }
        S=Tree[S].next[child];
    }
}

void Build_fail(int Star)       //建立失败指针
{
    int i,e,s,temp,now_fail;
    s=e=0;
    listb[s++]=Star;
    while(s!=e)
    {
        temp=listb[e++];
        for(i=0;i<26;i++)
        {
            if(Tree[temp].next[i]!=-1)
            {
                now_fail=Tree[temp].fail;
                while(now_fail!=-1)   //***!=-1
                {
                    if(Tree[now_fail].next[i]!=-1)
                    {
                        Tree[Tree[temp].next[i]].fail=Tree[now_fail].next[i];
                        break;
                    }
                    now_fail=Tree[now_fail].fail;
                }
                if(now_fail==-1)
                {
                    Tree[Tree[temp].next[i]].fail=0;
                }
                listb[s++]=Tree[temp].next[i];
            }
        }
    }
}


int Ac_auto(int x,int y,int fx)   //BFS匹配
{
    int i=0,p=0,temp,tempx,tempy,child,sum=0;
    while(1)
    {
        tempx=x+Fx[fx][0]*i;
        tempy=y+Fx[fx][1]*i;
        if(tempx<0||tempx>=n||tempy<0||tempy>=m)
            break;
        child=Map[tempx][tempy];
        while(Tree[p].next[child]==-1&&p!=0)
        {
            p=Tree[p].fail;
        }
        p=(Tree[p].next[child]==-1)?0:Tree[p].next[child];
        temp=p;
        while(Tree[temp].w!=-1&&temp!=0)
        {
            if(ans[Tree[temp].w].x==-1)
            {
                sum++;
                ans[Tree[temp].w].x=tempx;
                ans[Tree[temp].w].y=tempy;
                ans[Tree[temp].w].fx=fx;
            }
            temp=Tree[temp].fail;
        }
        i++;
    }
    return sum;
}


int main()
{
    int k,i,j,j1,num;
   	scanf("%d%d%d",&n,&m,&k);
	Index=1;num=0;
	memset(Map,-1,sizeof(Map));
	memset(ans,-1,sizeof(ans));
	memset(Tree,-1,sizeof(Tree));
	for(i=0;i<n;i++)
	{
		scanf("%s",ch1);
		for(j=0;j<m;j++)
		{
			Map[i][j]=ch1[j]-'A';
		}
	}
	for(i=1;i<=k;i++)
	{
		scanf("%s",ch1);
		ch1len[i]=strlen(ch1);
		Insert(0,ch1len[i],i);
	}
	Build_fail(0);
	for(i=0;i<n&&num<k;i++)    //行扫描
	{
		for(j1=0;j1<8&&num<k;j1++)
		{
			num+=Ac_auto(i,0,j1);
			num+=Ac_auto(i,m-1,j1);
		}
	}
	for(j=0;j<m&&num<k;j++)    //列扫描
	{
		for(j1=0;j1<8&&num<k;j1++)
		{
			num+=Ac_auto(n-1,j,j1);
			num+=Ac_auto(0,j,j1);
		}
	}
	for(i=1;i<=k;i++)
	{
		printf("%d %d %c\n",ans[i].x-(Fx[ans[i].fx][0]*(ch1len[i]-1)),ans[i].y-(Fx[ans[i].fx][1]*(ch1len[i]-1)),ans[i].fx+'A');
	}
    return 0;
}


你可能感兴趣的:(poj,AC自动机,1204)