银河

SKYIV STUDIO

  博客园 :: 首页 :: 博问 :: 闪存 :: :: :: 订阅 订阅 :: 管理 ::
  268 随笔 :: 2 文章 :: 2616 评论 :: 140万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
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

inputoutput
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 + 1continue;
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<charchar> theDictionary = null;
68     
69     Dictionary<charchar> 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 算法也可以用于这道题,且时间复杂度是线性的。


返回目录
posted on   银河  阅读(2960)  评论(2编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述
点击右上角即可分享
微信分享提示