Timus 1002. Phone numbers

Timus 1002. Phone numbers 要求根据所给的字典找出表示指定电话号码的单词序列。

1002. Phone numbers

Time Limit: 2.0 second
Memory Limit: 16 MB
In the present world you frequently meet a lot of call numbers and they are going to be longer and longer. You need to remember such a kind of numbers. One method to do it in an easy way is to assign letters to digits as shown in the following picture:
1 ij
4 gh
7 prs
2 abc
5 kl
8 tuv
0 oqz
3 def
6 mn
9 wxy
This way every word or a group of words can be assigned a unique number, so you can remember words instead of call numbers. It is evident that it has its own charm if it is possible to find some simple relationship between the word and the person itself. So you can learn that the call number 941837296 of a chess playing friend of yours can be read as WHITEPAWN, and the call number 2855304 of your favourite teacher is read BULLDOG.
Write a program to find the shortest sequence of words (i.e. one having the smallest possible number of words) which corresponds to a given number and a given list of words. The correspondence is described by the picture above.

Input

Input contains a series of tests. The first line of each test contains the call number, the transcription of which you have to find. The number consists of at most 100 digits. The second line contains the total number of the words in the dictionary (maximum is 50 000). Each of the remaining lines contains one word, which consists of maximally 50 small letters of the English alphabet. The total size of the input file doesn't exceed 300 KB. The last line of input file contains call number −1.

Output

Each line of output contains the shortest sequence of words which has been found by your program. The words are separated by single spaces. If there is no solution to the input data, the line contains text “ No solution.”. If there are more solutions having the minimum number of words, you can choose any single one of them.

Sample

input output
7325189087
5
it
your
reality
real
our
4294967296
5
it
your
reality
real
our
-1
reality our
No solution.
Problem Source: Central European Olympiad in Informatics 1999
解答如下:
 1  using  System;
 2  using  System.IO;
 3  using  System.Drawing;
 4  using  System.Collections.Generic;
 5 
 6  namespace  Skyiv.Ben.Timus
 7  {
 8     //   http://acm.timus.ru/problem.aspx?space=1 &num=1002
 9     sealed   class  T1002
10    {
11       static   void  Main()
12      {
13         new  T1002().Run(Console.In, Console.Out);
14      }
15      
16       void  Run(TextReader reader, TextWriter writer)
17      {
18         while  ( true )
19        {
20           string  phone  =  reader.ReadLine();
21           if  (phone  ==   " -1 " break ;
22           string [] words  =   new   string [ int .Parse(reader.ReadLine())];
23           string [] numbers  =   new   string [words.Length];
24           for  ( int  i  =   0 ; i  <  words.Length; i ++ )
25            numbers[i]  =  WordToNumber(words[i]  =  reader.ReadLine());
26           int [] idxs  =  GetMatchIndexs(phone, numbers);
27           if  (idxs  ==   null ) writer.Write( " No solution. " );
28           else   foreach  ( int  idx  in  idxs) writer.Write(words[idx]  +   "   " );
29          writer.WriteLine();
30        }
31      }
32      
33       int [] GetMatchIndexs( string  text,  string [] dict)
34      {
35         bool [] match  =   new   bool [text.Length  +   2 ];
36        match[ 1 =   true ;
37        CharacterRange[] list  =   new  CharacterRange[match.Length];
38         for  ( int  i  =   1 ; i  <  list.Length; i ++ ) list[i].Length  =  text.Length  +   1 ;
39         for  ( int  i  =   1 ; i  <=  text.Length; i ++ )
40        {
41           if  ( ! match[i])  continue ;
42           for  ( int  j  =   0 ; j  <  dict.Length; j ++ )
43          {
44             int  n  =  dict[j].Length;
45             if  (text.Length  -  i  +   1   <  n  ||  dict[j]  !=  text.Substring(i  -   1 , n))  continue ;
46            match[i  +  n]  =   true ;
47             if  (list[i  +  n  -   1 ].Length  <=  list[i  -   1 ].Length  +   1 continue ;
48            list[i  +  n  -   1 ].Length  =  list[i  -   1 ].Length  +   1 ;
49            list[i  +  n  -   1 ].First  =  j;
50          }
51        }
52         int  k  =  text.Length;
53         if  (list[k].Length  >  k)  return   null ;
54         int [] idxs  =   new   int [list[k].Length];
55         for  ( int  i  =  idxs.Length  -   1 ; i  >=   0 ; k  -=  dict[idxs[i]].Length, i -- )
56          idxs[i]  =  list[k].First;
57         return  idxs;
58      }
59      
60       string  WordToNumber( string  word)
61      {
62         char [] number  =   new   char [word.Length];
63         for  ( int  i  =   0 ; i  <  word.Length; i ++ ) number[i]  =  TheDictionary[word[i]];
64         return   new   string (number);
65      }
66      
67      Dictionary < char char >  theDictionary  =   null ;
68      
69      Dictionary < char char >  TheDictionary
70      {
71         get
72        {
73           if  (theDictionary  ==   null )
74          {
75            theDictionary  =   new  Dictionary < char , char > ();
76             for  ( int  i  =   0 ; i  <   26 ; i ++ )
77              theDictionary.Add(( char )( ' a '   +  i),  " 22233344115566070778889990 " [i]);
78          }
79           return  theDictionary;
80        }
81      }
82    }
83  }
84 

上述程序 16 - 31 行的 Run 方法循环读取输入,在 25 行调用 WordToNumber 方法(60 - 65 行)将字典中的英文单词转换为阿拉伯数字。然后在 26 行调用 GetMatchIndexs 方法在字典中寻找匹配的英文单词序列。最后在 27 - 29 行输出结果。

这个程序的核心是 33 - 58 行的 GetMatchIndexs 方法。布尔数组 match 表示在该点是否有一个匹配。CharacterRange 数组 list 用来记录匹配的情况,其 Length 属性表示到该点处已经匹配的单词数,First 属性表示在该点处匹配的单词在字典中的索引。该方法在 39 - 51 行遍历要匹配的文本(即电话号码),在每个匹配点遍历所给的字典以寻找下一个匹配点,如果下一个匹配点位于尚未匹配处或者到该点处已经匹配的单词数更大的话,就更新该处的匹配信息。最后,在 52 - 57 行返回匹配的单词序列在字典中的索引,其中第 53 行判断如果最后一个匹配点不在要匹配的文本的结尾则说明匹配失败。

据说 Aho-Corasick 算法也可以用于这道题,且时间复杂度是线性的。


返回目录

你可能感兴趣的:(number)