Timus 1002. Phone numbers 要求根据所给的字典找出表示指定电话号码的单词序列。
Problem Source: Central European Olympiad in Informatics 1999
解答如下:
返回目录
1002. Phone numbers
Time Limit: 2.0 second
Memory Limit: 16 MB
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. |
解答如下:
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
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 算法也可以用于这道题,且时间复杂度是线性的。
返回目录
分类:
算法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述