Description
Word puzzles are usually simple and very entertaining for all ages. They are so entertaining that Pizza-Hut company started using table covers with word puzzles printed on them, possibly with the intent to minimise their client's perception of any possible delay in bringing them their order.
Even though word puzzles may be entertaining to solve by hand, they may become boring when they get very large. Computers do not yet get bored in solving tasks, therefore we thought you could devise a program to speedup (hopefully!) solution finding in such puzzles.
The following figure illustrates the PizzaHut puzzle. The names of the pizzas to be found in the puzzle are: MARGARITA, ALEMA, BARBECUE, TROPICAL, SUPREMA, LOUISIANA, CHEESEHAM, EUROPA, HAVAIANA, CAMPONESA.
Input
The first line of input consists of three positive numbers, the number of lines, 0 < L <= 1000, the number of columns, 0 < C <= 1000, and the number of words to be found, 0 < W <= 1000. The following L input lines, each one of size C characters, contain the word puzzle. Then at last the W words are input one per line.
Output
Your program should output, for each word (using the same order as the words were input) a triplet defining the coordinates, line and column, where the first letter of the word appears, followed by a letter indicating the orientation of the word according to the rules define above. Each value in the triplet must be separated by one space only.
Sample Input
Sample Output
Source
Southwestern Europe 2002
http://acm.pku.edu.cn/JudgeOnline/problem?id=1204
首先按照数据结构书上的一个思路解决,主要思想是:将词典里面所有的单词放入哈西表,然后遍历表格,逐个检测表格中的字符串是否在哈西表中。采用这个基本思路,算法严重超时。然后再改进上面的算法,在哈西值的求取上,提前终止查找上都作了优化,主要是把词典中的每个词的所有前缀也放入哈西表,这样在查找的时候,可以提前终止在某个方向上的查找。优化之后,算法可以很快的求解出大部分的测试用例,但是对于一些特殊的用例,算法还要花10多秒才能完成。
分析了很久,发现用哈西表操作的话,基本已经做到了效率最高的方法了,没有找到可以进一步优化的地方。于是到网上问了一下高手,发现用trie树可以解决。于是调整了数据结构,将哈西表改为Trie树,以及对应的插入,查找等操作,主程序基本不用改。发现这个时候,效率确实有惊人的提高!可能用哈西表的方法,计算哈西值花的时间太多,而用trie树可以节省这个时间,直接进行比较。
用哈西表的代码:
#include <stdio.h>
#include <string.h>
struct Position
{
int i,j;
char orientation;
Position(int x, int y, char o) : i(x), j(y), orientation(o) {}
};
struct Node
{
const char* s;
Node* next;
Position* pos;
Node(const char* p, Node* n=NULL, Position* po=NULL) : s(p), next(n), pos(po) {}
};
char maze[1000][1001];//字符表
char word[1000][1001];//单词
int code[1000];//单词对应的散列值
const int TableSize = 109987;
bool prefix[TableSize]={0};
Node* HashTable[TableSize] = {NULL};
int Hash(const char* s, int size)
{
unsigned int val = 0;
while(*s!='/0')
{
val = (val<<5) + (*s-'A');
prefix[val%size] = 1;
s++;
}
return val % size;
}
void Insert(const char* s, int index)
{
//int index = Hash(s, TableSize);
Node* p = new Node(s,HashTable[code[index]]);
HashTable[code[index]] = p;
}
Node* Find(const char* s)
{
int index = Hash(s, TableSize);
Node* p = HashTable[index];
while(p!=NULL)
{
if(strcmp(p->s,s)==0)
break;
p = p->next;
}
return p;
}
Node* Find(const char* s, int index)
{
Node* p = HashTable[code[index]];
while(p!=NULL)
{
if(strcmp(p->s,s)==0)
break;
p = p->next;
}
return p;
}
Node* Find2(const char* s, int code)
{
Node* p = HashTable[code];
while(p!=NULL)
{
if(strcmp(p->s,s)==0)
break;
p = p->next;
}
return p;
}
int deltai[]={-1,-1,0,1,1,1,0,-1};
int deltaj[]={0,1,1,1,0,-1,-1,-1};
int L,C,W,i,j,k,len,maxlen=0;
char test[1001];
inline bool valid(int i, int j)
{
return (i>=0)&&(j>=0)&&(i<L)&&(j<C);
}
int main()
{
scanf("%d%d%d",&L,&C,&W);
for(i=0; i<L; ++i)
scanf("%s",maze[i]);
for(i=0; i<W; ++i)
{
scanf("%s",word[i]);
len = strlen(word[i]);
if(len>maxlen)
maxlen = len;
code[i] = Hash(word[i],TableSize);
Insert(word[i],i);
}
for(i=0; i<L; ++i)
{
for(j=0; j<C; ++j)
{
for(k=0; k<8; ++k)//八个方向
{
int l = 1;
int x = i;
int y = j;
unsigned int val = 0;
while(l<=maxlen && valid(x,y))
{
test[l-1] = maze[x][y];
test[l]='/0';
val = (val<<5) + (test[l-1]-'A');
int hashCode = val % TableSize;
if(!prefix[hashCode])
break;
Node* pNode = Find2(test,hashCode);
if(pNode!=NULL && pNode->pos==NULL)
{
pNode->pos = new Position(i,j,'A'+k);
}
++l;
x += deltai[k];
y += deltaj[k];
}
}
}
}
for(i=0; i<W; ++i)
{
Node* pNode = Find(word[i],i);
printf("%d %d %c/n", pNode->pos->i, pNode->pos->j, pNode->pos->orientation);
}
return 0;
}
用TRIE树的代码:
#include <stdio.h>
#include <string.h>
struct Position
{
int i,j;
char orientation;
Position(int x, int y, char o) : i(x), j(y), orientation(o) {}
};
struct Node
{
bool wordEnd;
Node* child[26];
Position* pos;
Node(bool isWordEnd = false, Position* position = NULL) : wordEnd(isWordEnd), pos(position)
{
for(int i=0; i<26; ++i)
child[i] = NULL;
}
};
char maze[1000][1001];//字符表
char word[500][1001];//单词
void Insert(Node* root, char* s)
{
char* ps = s;
Node* pn = root;
while(*ps != '/0')
{
int index = *ps - 'A';
if(pn->child[index]==NULL)
{
pn->child[index] = new Node();
if(*(ps+1)=='/0')
pn->child[index]->wordEnd = true;
}
pn = pn->child[index];
++ps;
}
}
Node* Find(Node* root, char* s)
{
char* ps = s;
Node* pn = root;
while(*ps != '/0')
{
int index = *ps - 'A';
if(pn->child[index]==NULL)
return NULL;
pn = pn->child[index];
++ps;
}
if(pn!=NULL && pn->wordEnd)
return pn;
return NULL;
}
inline Node* PortionFind(Node* startFindNode, char c)
{
return startFindNode->child[c-'A'];
}
int deltai[]={-1,-1,0,1,1,1,0,-1};
int deltaj[]={0,1,1,1,0,-1,-1,-1};
int L,C,W,i,j,k,len,maxlen=0;
char test[1001];
int cnt = 0;
inline bool valid(int i, int j)
{
return (i>=0)&&(j>=0)&&(i<L)&&(j<C);
}
int main()
{
Node *root = new Node();
scanf("%d%d%d",&L,&C,&W);
for(i=0; i<L; ++i)
scanf("%s",maze[i]);
for(i=0; i<W; ++i)
{
scanf("%s",word[i]);
len = strlen(word[i]);
if(len>maxlen)
maxlen = len;
Insert(root,word[i]);
}
for(i=0; i<L; ++i)
{
for(j=0; j<C; ++j)
{
for(k=0; k<8; ++k)//八个方向
{
int l = 1;
int x = i;
int y = j;
Node *startNode = root;
while(l<=maxlen && valid(x,y))
{
test[l-1] = maze[x][y];
test[l]='/0';
Node* pNode = PortionFind(startNode,test[l-1]);
if(pNode==NULL)
break;
if(pNode->wordEnd && pNode->pos==NULL)
{
pNode->pos = new Position(i,j,'A'+k);
cnt++;
if(cnt==W) goto PRINT;
}
++l;
x += deltai[k];
y += deltaj[k];
startNode = pNode;
}
}
}
}
PRINT:
for(i=0; i<W; ++i)
{
Node* pNode = Find(root,word[i]);
printf("%d %d %c/n", pNode->pos->i, pNode->pos->j, pNode->pos->orientation);
}
return 0;
}
开始求哈西值的时候,没有注意优先级,移位操作符的优先级要低于四则运算的优先级,导致每次求出的值都是0
不过看到高手的算法的效率还是比我这个高,运行时间只有我的一半,还得向他们请教啊!
0 15 G 2 11 C 7 18 A 4 8 C 16 13 B 4 15 E 10 3 D 5 1 E 19 7 C 11 11 H
20 20 10 QWSPILAATIRAGRAMYKEI AGTRCLQAXLPOIJLFVBUQ TQTKAZXVMRWALEMAPKCW LIEACNKAZXKPOTPIZCEO FGKLSTCBTROPICALBLBC JEWHJEEWSMLPOEKORORA LUPQWRNJOAAGJKMUSJAE KRQEIOLOAOQPRTVILCBZ QOPUCAJSPPOUTMTSLPSF LPOUYTRFGMMLKIUISXSW WAHCPOIYTGAKLMNAHBVA EIAKHPLBGSMCLOGNGJML LDTIKENVCSWQAZUAOEAL HOPLPGEJKMNUTIIORMNC LOIUFTGSQACAXMOPBEIO QOASDHOPEPNBUYUYOBXB IONIAELOJHSWASMOUTRK HPOIYTJPLNAQWDRIBITG LPOINUYMRTEMPTMLMNBO PAFCOPLHAVAIANALBPFS MARGARITA ALEMA BARBECUE TROPICAL SUPREMA LOUISIANA CHEESEHAM EUROPA HAVAIANA CAMPONESA
Your task is to produce a program that given the word puzzle and words to be found in the puzzle, determines, for each word, the position of the first letter and its orientation in the puzzle.
You can assume that the left upper corner of the puzzle is the origin, (0,0). Furthemore, the orientation of the word is marked clockwise starting with letter A for north (note: there are 8 possible directions in total).