思路:字典树
分析:
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;
}