Poj1204

题目大意:给你一个字母表格,问你在这些字母表格中是否存在下面所给的字符串,如果存在的话给出字符串首字母的起始坐标,已经搜寻方向。

算法思路:一开始直接暴力深搜,从每个满足条件的首字母开始,递归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;
}



猜你喜欢

转载自huyifan951124.iteye.com/blog/2316159