题目大意:给你一个字母表格,问你在这些字母表格中是否存在下面所给的字符串,如果存在的话给出字符串首字母的起始坐标,已经搜寻方向。
算法思路:一开始直接暴力深搜,从每个满足条件的首字母开始,递归8个方向,结果超时,于是去学习了字典树。如果不明白什么是字典树,可自行了解,网上的很多博客都有详细的介绍和实现代码。后来对于这道题,我发现字典树快就快在如果一个字符串是另一个字符串的前缀,直接深搜要找两遍,而字典树直接一边就得出了结果,我想优化就优化在这里吧。。。(理解不正确的话还请指正)。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char c[1005][1005];
int n,m,w,sx,sy;
int out[1005][3];
char str[1005];
int dx[8]={-1,-1,0,1,1,1,0,-1};
int dy[8]={0,1,1,1,0,-1,-1,-1};
typedef struct Trie
{
Trie *next[26];
int v;
int id;
};
Trie *root;
void createTrie(int num)
{
Trie *p=root,*q;
for(int i=0;i<strlen(str);i++)
{
int id=str[i]-'A';
if(p->next[id]==NULL)
{
p->next[id]=new Trie();
p=p->next[id];
}
else
{
p->next[id]->v++;
p=p->next[id];
}
}
p->id=num;
}
void dfs(Trie *p,int x,int y,int dir)
{
if(p==NULL)
{
return;
}
if(p->id>0) //在这里不能返回,不然的只遍历了前缀子串就返回了,无法达到减少时间复杂度的目的
{
out[p->id][0]=sx;
out[p->id][1]=sy;
out[p->id][2]=dir;
}
if(x<0||x>=n||y<0||y>=m)
return;
dfs(p->next[c[x][y]-'A'],x+dx[dir],y+dy[dir],dir); //减少了前缀子串的重新遍历
}
int main()
{
scanf("%d%d%d",&n,&m,&w);
for(int i=0; i<n; i++)
{
getchar();
for(int j=0; j<m; j++)
{
scanf("%c",&c[i][j]);
}
}
root=new Trie();
for(int i=1;i<=w;i++)
{
scanf("%s",str);
createTrie(i); //将所有要查询的字符串构成一个字典树
}
Trie *p=root;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
for(int k=0;k<8;k++)
{
sx=i;
sy=j;
dfs(p,i,j,k);
}
}
}
for(int i=1;i<=w;i++)
{
printf("%d %d %c\n",out[i][0],out[i][1],out[i][2]+'A');
}
return 0;
}