【ICPC-262】hdu 1857 Word Puzzle

点击打开链接hdu 1857

 

思路:字典树

分析:
1 题目要求的是给定的单词第一个字母在这个矩形里面的最小的坐标
2 矩形的最大500*500,单词的来源有三个方向,并且单词的起点和终点在矩形之内都是可能的。所以的如果利用枚举矩形之内的单词,那么肯定是超内存的
3 所以我们必须考虑另一种的方法就是对单词进行建字典树,那么我们只要去枚举单词的可能的起点,然后进行查找相应的单词是不是在树上,如果是的话就标记一下当前的坐标。
4 注意由于单词的来源有三个方向,但是因为要求的如果下相同的情况下要求坐标先r最小然后在c最小,所以应该要注意枚举三个方向的顺序。

代码:


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

#define MAXN 1000010
#define MAX 510
#define N 30

int cnt , n , m;
int dir[3][2] = {{0,1},{1,0},{1,1}};
char maze[MAX][MAX];
char words[10010][MAX];
struct Point{
   int x;
   int y;
}p[10010];
struct Trie{
   int flag;
   Trie *child[N];
}trie[MAXN];
Trie* root;

/*静态分配空间*/
Trie* newTrie(){
   trie[cnt].flag = -1;
   for(int i = 0 ; i < N ; i++)
     trie[cnt].child[i] = NULL;
   return &trie[cnt++];
}

/*字典树的插入*/
void insert(char *str , int num){
    Trie *s = root;
    int len = strlen(str);
    for(int i = 0 ; i < len ; i++){
       int num = str[i]-'A';
       if(s->child[num] == NULL)
         s->child[num] = newTrie();
       s = s->child[num];
    }
    s->flag = num;/*flag标记为是第几个单词*/
}

/*判断是否在矩形之内*/
bool judge(int x , int y){
   if(x >= 0 && y >= 0 && x < n && y < m)
     return true;
   return false;
}

/*字典树的查找*/
void search(int x , int y , int k){
    Trie *s = root;
    int tmp_x , tmp_y;
    tmp_x = x , tmp_y = y;
    while(judge(x  , y)){
        int num = maze[x][y]-'A';
        if(s->child[num] == NULL)
          return;
        s = s->child[num];
        if(s->flag != -1){/*编号不是-1*/
           int num = s->flag;
           if(p[num].x == -1){
             p[num].x = tmp_x;
             p[num].y = tmp_y;
             /*这里不能直接break,因为可能其它的单词以它为前缀*/
           }
        }
        x += dir[k][0];
        y += dir[k][1];
    }
}

int main(){
   int t = 0;
   cnt = 0;
   root = newTrie();
   scanf("%d%d%*c" , &n , &m);
   for(int i = 0 ; i < n ; i++){
      for(int j = 0 ; j < m ; j++)
         scanf("%c" , &maze[i][j]);
      getchar();
   }
   /*建字典树*/
   while(scanf("%s" , words[t]) && strcmp(words[t] , "-1") != 0){
      insert(words[t] , t);
      p[t].x = p[t].y = -1;
      t++;
   }
   /*枚举三个方向的起点*/
   for(int i = 0 ; i < n ; i++){
      for(int j = 0 ; j < m ; j++){
         for(int k = 0 ; k < 3 ; k++)
            search(i , j , k);
      }
   }
   /*输出*/
   for(int i = 0 ; i < t ; i++)
      printf("%d %d\n" , p[i].x , p[i].y);
   return 0;
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值