题意
给出有一个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;
}

本文介绍了一道关于AC自动机的地图匹配题目,通过反向构建自动机的方法,在一个字符地图中查找指定字符串首次出现的位置及方向。文章详细解释了解题思路,包括构建自动机的过程、搜索算法实现细节等。
856

被折叠的 条评论
为什么被折叠?



