题目:http://acm.jlu.edu.cn/joj/showproblem.php?pid=1058
算法:Trie树,广度优先搜索
思路:把字典建成一个Trie树,每次处理一个按键序列时,都建立一个队列,循环处理,初始循环时,Trie的根结点入队,每次循环时,遍历当前在队列中的每一个结点的所有子结点,把它们的子结点当中与当前所处理的按键相同的结点入队,全部入队完毕后,选中当前队列中的优先级最高的结点,输出从根结点到该结点的路径,然后开始新一轮循环,处理按键序列中的下一个按键。
这个题目还可以用另一种方法来做,就是在读入字典的时候,同时生成当前单词的按键序列。然后读入按键序列后,在字典中顺序查找,在查找过程中,把前缀相同的单词的优先级要累加起来。感觉还是使用Trie树更简单些。
使用Trie树的代码如下:
- /* {JOJ1058:T9}
- * Date & Time: Thu Oct 09 19:42:13 2008
- * File: 1058.c
- * Author: WangHaibin
- * Platform: windows xp sp2, emacs 22.1, gcc, gdb
- *
- * Algorithm: Trie树,广度搜索
- *
- * State: Acceptd, 0.00s, 416K
- * */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- typedef struct _tn {
- char letter;
- int frequency;
- char belongTo;
- struct _tn *child, *brother, *parent;
- char isComplete;
- } TrieNode;
- TrieNode *root;
- char belongTo[26] = {'2','2','2','3','3','3','4','4','4','5','5','5','6','6','6',
- '7','7','7','7','8','8','8','9','9','9','9'};
- void insert(const char* word, int freq) {
- TrieNode *p = root, *oldBrother = NULL, *dest = root->child;
- int k = 0, len = strlen(word);
- for(k = 0; k < len; k++) {
- while(dest != NULL && dest->letter != word[k]) {
- oldBrother = dest, dest = dest->brother;
- }
- if(dest) {
- dest->frequency += freq;
- } else {
- /* dest is NULL, word[0] not found */
- dest = (TrieNode*)malloc(sizeof(TrieNode));
- dest->letter = word[k];
- dest->frequency = freq;
- dest->parent = p;
- dest->brother = NULL;
- dest->child = NULL;
- dest->belongTo = belongTo[word[k]-'a'];
- dest->isComplete = 0;
- if(oldBrother) {
- oldBrother->brother = dest;
- } else {
- /* oldBrother为空,说明p的子树为空 */
- p->child = dest;
- }
- }
- p = dest;
- dest = p->child;
- oldBrother = NULL;
- }
- p->isComplete = 1;
- }
- void solve(const char* seq) {
- TrieNode *queue[1024];
- int front = 0, rear = 0, k = 0, i, j, maxfreq;
- TrieNode *curLayer;
- char path[128] = {0};
- queue[rear++] = root;
- while(seq[k] != '1') {
- i = rear - front;
- for(j = 1; j <= i; j++) {
- curLayer = queue[front]->child;
- front++;
- while(curLayer) {
- if(curLayer->belongTo == seq[k]) {
- queue[rear++] = curLayer;
- }
- curLayer = curLayer->brother;
- }
- }
- if(front == rear) {
- /* queue is empty */
- printf("MANUALLY/n");
- k++;
- continue;
- }
- for(i = front + 1, maxfreq = queue[front]->frequency, j = front; i < rear; i++) {
- if(queue[i]->frequency > maxfreq) {
- maxfreq = queue[i]->frequency;
- j = i;
- }
- }
- curLayer = queue[j]->parent;
- i = 126;
- path[i] = queue[j]->letter;
- while(curLayer != root) {
- path[--i] = curLayer->letter;
- curLayer = curLayer->parent;
- }
- printf("%s/n", path+i);
- k++;
- }
- }
- void deleteTree(TrieNode* t) {
- if(t != NULL) {
- deleteTree(t->child);
- deleteTree(t->brother);
- free(t);
- }
- }
- int main() {
- int n, w, p, m, i;
- char word[128], seq[128];
- root = (TrieNode*)malloc(sizeof(TrieNode));
- root->child = NULL;
- root->brother = NULL;
- /*freopen("in.txt", "r", stdin);*/
- scanf("%d", &n);
- for(i = 1; i <= n; i++) {
- scanf("%d", &w);
- while(w--) {
- scanf("%s%d", word, &p);
- insert(word, p);
- }
- scanf("%d", &m);
- printf("Scenario #%d:/n", i);
- while(m--) {
- scanf("%s", seq);
- solve(seq);
- printf("/n");
- }
- deleteTree(root->child);
- root->child = NULL;
- root->brother = NULL;
- printf("/n");
- }
- return 0;
- }