hud 1298 T9(字典樹 + DFS詳解)

http://acm.hdu.edu.cn/showproblem.php?pid=1298
Problem Description
A while ago it was quite cumbersome to create a message for the Short Message Service (SMS) on a mobile phone. This was because you only have nine keys and the alphabet has more than nine letters, so most characters could only be entered by pressing one key several times. For example, if you wanted to type “hello” you had to press key 4 twice, key 3 twice, key 5 three times, again key 5 three times, and finally key 6 three times. This procedure is very tedious and keeps many people from using the Short Message Service.

This led manufacturers of mobile phones to try and find an easier way to enter text on a mobile phone. The solution they developed is called T9 text input. The “9” in the name means that you can enter almost arbitrary words with just nine keys and without pressing them more than once per character. The idea of the solution is that you simply start typing the keys without repetition, and the software uses a built-in dictionary to look for the “most probable” word matching the input. For example, to enter “hello” you simply press keys 4, 3, 5, 5, and 6 once. Of course, this could also be the input for the word “gdjjm”, but since this is no sensible English word, it can safely be ignored. By ruling out all other “improbable” solutions and only taking proper English words into account, this method can speed up writing of short messages considerably. Of course, if the word is not in the dictionary (like a name) then it has to be typed in manually using key repetition again.

這裏寫圖片描述

More precisely, with every character typed, the phone will show the most probable combination of characters it has found up to that point. Let us assume that the phone knows about the words “idea” and “hello”, with “idea” occurring more often. Pressing the keys 4, 3, 5, 5, and 6, one after the other, the phone offers you “i”, “id”, then switches to “hel”, “hell”, and finally shows “hello”.

Write an implementation of the T9 text input which offers the most probable character combination after every keystroke. The probability of a character combination is defined to be the sum of the probabilities of all words in the dictionary that begin with this character combination. For example, if the dictionary contains three words “hell”, “hello”, and “hellfire”, the probability of the character combination “hell” is the sum of the probabilities of these words. If some combinations have the same probability, your program is to select the first one in alphabetic order. The user should also be able to type the beginning of words. For example, if the word “hello” is in the dictionary, the user can also enter the word “he” by pressing the keys 4 and 3 even if this word is not listed in the dictionary.

Input
The first line contains the number of scenarios.

Each scenario begins with a line containing the number w of distinct words in the dictionary (0<=w<=1000). These words are given in the next w lines. (They are not guaranteed in ascending alphabetic order, although it’s a dictionary.) Every line starts with the word which is a sequence of lowercase letters from the alphabet without whitespace, followed by a space and an integer p, 1<=p<=100, representing the probability of that word. No word will contain more than 100 letters.

Following the dictionary, there is a line containing a single integer m. Next follow m lines, each consisting of a sequence of at most 100 decimal digits 2-9, followed by a single 1 meaning “next word”.

Output
The output for each scenario begins with a line containing “Scenario #i:”, where i is the number of the scenario starting at 1.

For every number sequence s of the scenario, print one line for every keystroke stored in s, except for the 1 at the end. In this line, print the most probable word prefix defined by the probabilities in the dictionary and the T9 selection rules explained above. Whenever none of the words in the dictionary match the given number sequence, print “MANUALLY” instead of a prefix.

Terminate the output for every number sequence with a blank line, and print an additional blank line at the end of every scenario.

Sample Input
2
5
hell 3
hello 4
idea 8
next 8
super 3
2
435561
43321
7
another 5
contest 6
follow 3
give 13
integer 6
new 14
program 4
5
77647261
6391
4681
26684371
77771

Sample Output
Scenario #1:
i
id
hel
hell
hello

i
id
ide
idea

Scenario #2:
p
pr
pro
prog
progr
progra
program

n
ne
new

g
in
int

c
co
con
cont
anoth
anothe
another

p
pr
MANUALLY
MANUALLY

題目大意:傳統的九鍵輸入法比較麻煩,現在有一種改進的輸入法,就是您只需簡單地開始輸入,而無需重複多次,並且軟件使用內置字典查找“最可能”匹配輸入的單詞,題目上給你一些單詞和每個單詞出現的頻率,再給你一些由數字組成的字符串,以‘1’結尾,要求每輸入一個字母輸出這次最可能匹配輸出哪些字符串。

解題思路:臭長臭長的題,看了好久纔看完,看完之後可以很明顯的感覺到這個題要用字典樹來寫,因爲我們要記錄每個字符出現的頻率。而且每輸入一個數字時我們只需要保證這 個字符在字典樹中這一層出現的頻率最大,而且從根節點到這個節點的字符都包括在以前的數字中。雖然有了思路但感覺還是不太好實現,看來別人的處理方法,感覺太巧妙了。詳解見代碼。
CODE:

#include <bits/stdc++.h>

using namespace std;
char phone[][4] = {{'a','b','c'},{'d','e','f'},{'g','h','i'},{'j','k','l'},{'m','n','o'},{'p','q','r','s'},{'t','u','v'},{'w','x','y','z'}};
int num[8] = {3,3,3,3,3,4,3,4},w;
char ans[105],s[105],str[105];
/*
首先做好預處理,phone表示手機上九鍵表示的字母,num表示(除1外)每個數字上包含幾個字母,
w保存每個字符在字典樹每層出現的頻率
*/
struct Trie
{
    int cnt;///cnt記錄每個字母出現的頻率
    Trie *child[26];
    Trie()
    {
        cnt = 0;
        for(int i=0;i<26;i++)
            child[i] = NULL;
    }
};
Trie *root,*current,*temp;
void insert(char ss[],int k)
{
     current = root;
     for(int i=0;i<strlen(ss);i++)
     {
         if(current->child[ss[i]-'a'] == NULL){
            temp = new Trie;
            current->child[ss[i] - 'a'] = temp;
            current = current->child[ss[i]-'a'];
            (current->cnt)+=k;///在出入時記錄好每個字符出現的頻率
         }
         else{
            current = current->child[ss[i]-'a'];
            (current->cnt)+=k;
         }
     }
}
void dfs(int st,int len,Trie *tr)
///DFS查找的思路是遍歷這個數字包含的所有字符,如果在字典樹中出現就繼續遞歸往下找,
///直到找到題目所要求的長度,找到其中權重最大一個字符,並輸出從根節點到這個字符所表示的字符串
{
    if(st == len)///找到題目所要求長度
    {
        if(tr->cnt>w){
            w = tr->cnt;
            for(int i=0;i<len;i++)
                ans[i] = s[i];
            ans[len] = '\0';
        }
        return;
    }
    int L = str[st] - '2';///因爲包含字母的數字是從2開始的,所以這裏要減去‘2’
    for(int i=0;i<num[L];i++)
    {
        char c = phone[L][i];
        if(tr->child[c-'a']!=NULL){///因爲找到權重最大的字符時,它前邊的字符必須可能在以前輸入數字時有出現的可能,所以這裏我們要控制某個數字包含的字母只有在字典書中的字符才往下遞歸
            s[st] = c;
            dfs(st+1,len,tr->child[c-'a']);
        }
    }
}
int main()
{
    int T;scanf("%d",&T);
    int c=0;
    while(T--)
    {
        root = new Trie;
        int n,k;scanf("%d",&n);
        char str1[105];
        for(int i=0;i<n;i++)
        {
            scanf("%s %d",str1,&k);
            insert(str1,k);///字典樹插入
        }
        int m;
        scanf("%d",&m);

        for(int i=0;i<m;i++){
            scanf("%s",str);
            if(i==0)
                printf("Scenario #%d:\n",++c);
            int len = strlen(str);
            for(int j=1;j<len;j++){///因爲最後一個1忽略不計,所以這裏小於len就可以了
                w = 0;
                dfs(0,j,root);
                if(w>0)
                    printf("%s\n",ans);
                else
                    printf("MANUALLY\n");
            }
            printf("\n");
        }
        printf("\n");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章