题目大意:给你一个字母表格,问你在这些字母表格中是否存在下面所给的字符串,如果存在的话给出字符串首字母的起始坐标,已经搜寻方向。
算法思路:一开始直接暴力深搜,从每个满足条件的首字母开始,递归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; }