[poj1204][caioj1465][AC自动机]地图匹配

来源:互联网 发布:怎么查看手机端口号 编辑:程序博客网 时间:2024/06/03 22:48

题意

给出有一个L*C的字符地图,地图的行与列都从0开始编号
然后给出一些字符串,求出这些字符串在字符地图上第一次出现的坐标
输出字符串第一个字母的坐标和字符串的方向
字符串的方向是指字符串的走向
A表示正北,B表示东北,C表示正东,D表示东南,E表示正南,F表示西南,G表示正西,H表示西北
且保证字符串的方向是固定的

输入格式

第一行输入L,C,W(0 小于 L,C,W<=1000)
L表示行数,C表示列数,W表示字符串的数量
然后输入L*C的字符矩阵
最后输入W行字符串

输出格式

输出W行,每行对应第i个字符串第一个字母的坐标和字符串的方向

样例输入

20 20 10
QWSPILAATIRAGRAMYKEI
AGTRCLQAXLPOIJLFVBUQ
TQTKAZXVMRWALEMAPKCW
LIEACNKAZXKPOTPIZCEO
FGKLSTCBTROPICALBLBC
JEWHJEEWSMLPOEKORORA
LUPQWRNJOAAGJKMUSJAE
KRQEIOLOAOQPRTVILCBZ
QOPUCAJSPPOUTMTSLPSF
LPOUYTRFGMMLKIUISXSW
WAHCPOIYTGAKLMNAHBVA
EIAKHPLBGSMCLOGNGJML
LDTIKENVCSWQAZUAOEAL
HOPLPGEJKMNUTIIORMNC
LOIUFTGSQACAXMOPBEIO
QOASDHOPEPNBUYUYOBXB
IONIAELOJHSWASMOUTRK
HPOIYTJPLNAQWDRIBITG
LPOINUYMRTEMPTMLMNBO
PAFCOPLHAVAIANALBPFS
MARGARITA
ALEMA
BARBECUE
TROPICAL
SUPREMA
LOUISIANA
CHEESEHAM
EUROPA
HAVAIANA
CAMPONESA

样例输出

0 15 G
2 11 C
7 18 A
4 8 C
16 13 B
4 15 E
10 3 D
5 1 E
19 7 C
11 11 H

题解

ac自动机好题。。MLE炸了我好久。。
首先对单词建自动机,一定要反着来建!!
为什么??顺着跑你怎么记录起始点?八个方向一个个退回去?
所以说反着建啊。搜到s>0了也就到头了,直接记录x,y
反着建了然后暴力搜索,枚举结尾枚举方向扔进自动机
就这样切。。切记不要对图建自动机。。对角线长度建还不炸?

#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>#include<queue>using namespace std;const int dx[8]={-1,-1,0,1,1,1,0,-1};const int dy[8]={0,1,1,1,0,-1,-1,-1};struct trnode{    int s,fail,c[27];    bool vis;    trnode(){s=fail=0;vis=false;memset(c,-1,sizeof(c));}}tr[500010];int tot,root;char s[1005];struct node{    int x,y,w;}a[1005];void clean(int x){    tr[x].s=tr[x].fail=0;tr[x].vis=false;    for(int i=1;i<=26;i++)tr[x].c[i]=-1;}void add(int root,int p){    int len=strlen(s),x=root;    for(int i=len-1;i>=0;i--)    {        int y=s[i]-'A'+1;        if(tr[x].c[y]==-1)        {            tr[x].c[y]=++tot;            clean(tot);        }        x=tr[x].c[y];    }    tr[x].s=p;}queue<int>q;void build_fail(){    q.push(0);    while(!q.empty())    {        int x=q.front();        q.pop();        for(int i=1;i<=26;i++)        {            int son=tr[x].c[i];            if(son==-1)continue;            if(x==0)tr[son].fail=0;            else            {                int j=tr[x].fail;                while(j && tr[j].c[i]==-1)j=tr[j].fail;                tr[son].fail=max(tr[j].c[i],0);            }            q.push(son);        }    }}int n,m,member;char map[1001][1001];inline bool check(int x,int y){    if(x>=0 && x<n && y>=0 && y<m)return true;    return false;}void Find(int x,int y,int w){    int m=0;    while(check(x,y)==true)    {        int j=map[x][y]-'A'+1;        while(m!=0 && tr[m].c[j]==-1)m=tr[m].fail;        if(tr[m].c[j]!=-1)m=tr[m].c[j];        for(int k=m;k!=0 && tr[k].vis==false;k=tr[k].fail)        {            if(tr[k].s>0)            {                int l=tr[k].s;                a[l].x=x;a[l].y=y;                a[l].w=(w+4)%8;            }            tr[k].vis=true;        }        x+=dx[w];y+=dy[w];    }}int main(){    scanf("%d%d%d",&n,&m,&member);    clean(0);tot=0;    for(int i=0;i<n;i++)scanf("%s",map[i]);    for(int i=1;i<=member;i++)    {        scanf("%s",s);        add(0,i);    }    build_fail();    for(int i=0;i<n;i++)        Find(i,0,1),Find(i,0,2),Find(i,0,3),Find(i,m-1,5),Find(i,m-1,6),Find(i,m-1,7);    for(int j=0;j<m;j++)        Find(0,j,3),Find(0,j,4),Find(0,j,5),Find(n-1,j,0),Find(n-1,j,1),Find(n-1,j,7);    for(int i=1;i<=member;i++)printf("%d %d %c\n",a[i].x,a[i].y,a[i].w+'A');    return 0;}
原创粉丝点击