题目

题目描述

在一个农场里面,每一头牛都有一个数字编号,但是现在这些牛不喜欢这种编号,它们想把这些数字编号转化成为可以接受的字母的形式。数字与字母的转换表如下:

2: A,B,C 5: J,K,L 8: T,U,V

3: D,E,F 6: M,N,O 9: W,X,Y

4: G,H,I 7: P,R,S

每一个数字可以对应三个字母。但是并不是每一种由数字转化成的名字都被牛所接受,这些牛所能接受的名字在一个叫做dict.txt文件中。产生出来的名字,如果也存在于这个可接受的名字文件中,那么就表示这个名字是可以使用的。

例如:编号4734可以转化成为下列这么多名字,足足有81个之多。

GPDG GPDH GPDI GPEG GPEH GPEI GPFG GPFH GPFI GRDG GRDH GRDI
GREG GREH GREI GRFG GRFH GRFI GSDG GSDH GSDI GSEG GSEH GSEI
GSFG GSFH GSFI HPDG HPDH HPDI HPEG HPEH HPEI HPFG HPFH HPFI
HRDG HRDH HRDI HREG HREH HREI HRFG HRFH HRFI HSDG HSDH HSDI
HSEG HSEH HSEI HSFG HSFH HSFI IPDG IPDH IPDI IPEG IPEH IPEI
IPFG IPFH IPFI IRDG IRDH IRDI IREG IREH IREI IRFG IRFH IRFI
ISDG ISDH ISDI ISEG ISEH ISEI ISFG ISFH ISFI

但是这81个名字只有一个GREG是可以接受的(因为它存在于dict.txt中)

现在我们需要做的是,对于每一个输入的数字编号,都对应输出它转化成名字之后的所有的可以接受的名字。当名字有多个的时候我们需要按照字典序输出。如果没有一个是可以接受的,那么输出NONE

数据范围

  1. 输入的数字编号的长度不超过12个数字。
  2. dict.txt中共有不超过5000个名字。

样例输入

4734

样例输出

GREG

解题思路

我们首先考虑的第一种直接的想法就是,我们先将所给的数字转化成可能的名字,然后对每一个名字都去dict.txt中查找,看这个名字有没有出现过,如果有我们就输出。最后如果一个都没有输出就输出NONE。因为dict.txt中的所有名字已经是字典序排列的,所以我们不需要将它进行排序。

但是考虑一下时间复杂度,如果所给的数字编号长度为12,那么这个编号总共可以产生3^12个名字,对于每一个名字我们需要在名字列表中进行查找。所以最坏的时间复杂度需要O(3^12 * 5000),这个复杂度太高了(我测试了一下,这种写法会超时),那么我们如何进行优化呢?我们的第一个想法是在名字列表中进行查找的时候我们利用二分查找,这样可以将时间复杂度降低为O(3^12 * log5000),这是一个进步了。我们再接着思考一下,能不能继续优化呢?我们思考之后发现,其实名字列表中有很多名字长度跟我们的数字编号长度不一样,这些名字可以在第一时刻去除掉,这样我们可以将我们的查找列表减少。这样我们可以保证将时间复杂度控制在一个不错的范围了。

Tip:这个题目还有一个比较重要的地方那就是如何来从文件中获取可以接受的名字列表。

解题代码

/*
ID: yinzong2
PROG: namenum
LANG: C++11
*/
#define MARK
#include<cstdio>
#include<cstdlib>
#include<cstring> using namespace std;
const int maxn = 15; char mp[10][3] = { {'\0', '\0', '\0'}, {'\0', '\0', '\0'},
{'A', 'B', 'C'}, {'D', 'E', 'F'},
{'G', 'H', 'I'}, {'J', 'K', 'L'},
{'M', 'N', 'O'}, {'P', 'R', 'S'},
{'T', 'U', 'V'}, {'W', 'X', 'Y'}};
char inStr[maxn];
char dict[5000][maxn];
int dictCnt; bool flag; void init(int len) {
freopen("dict.txt", "r", stdin);
dictCnt = 0;
while(~scanf("%s", dict[dictCnt])) {
//过滤掉长度不同的名字
if(strlen(dict[dictCnt]) == len) {
dictCnt++;
}
}
} //普通的查找方法
//void searchStr(char s[]) {
// for(int i = 0; i < dictCnt; i++) {
// if(strcmp(s, dict[i]) == 0) {
// flag = true;
// printf("%s\n", dict[i]);
// break;
// }
// }
//} //二分查找
void searchStr(char s[]) {
int l = 0, r = dictCnt-1;
int mid;
int cnt = 1;
while(l <= r && cnt <= 100) {
mid = (l+r)/2;
int cmp = strcmp(s, dict[mid]);
if(cmp == 0) {
flag = true;
printf("%s\n", s);
break;
} else if(cmp < 0) {
r = mid-1;
} else {
l = mid+1;
}
cnt++;
}
} void make(int cur, int len, char newStr[]) {
if(cur == len) {
newStr[cur] = '\0';
searchStr(newStr);
return ;
}
int id = inStr[cur]-'0';
for(int i = 0; i < 3; i++) {
newStr[cur] = mp[id][i];
make(cur+1, len, newStr);
}
} int main() {
#ifdef MARK
freopen("namenum.in", "r", stdin);
freopen("namenum.out", "w", stdout);
#endif // MARK
while(~scanf("%s", inStr)) {
int len = strlen(inStr);
init(len);
flag = false;
char newStr[maxn];
make(0, len, newStr);
if(!flag) {
printf("NONE\n");
}
}
return 0;
}

解题思路(Type 2)

我们其实可以逆向思考一下,既然名字列表中的所有名字都是可以接受的,而且每一个字母只对应唯一的一个数字,那么我们是不是可以先将名字列表中的所有名字都转化成为数字编号,然后再跟我们输入的数字编号进行匹配,如果相同那么我们就直接输出这个可以接受的名字。这样程序简洁许多,最坏的时间复杂度为O(5000 * 12)

解题代码(Type 2)

/*
ID: yinzong2
PROG: namenum
LANG: C++11
*/
#define MARK
#include<cstdio>
#include<cstring>
#include<map> using namespace std;
const int maxn = 15; char num[maxn];
char str[maxn];
bool flag;
map<char, char>mp; void init() {
mp.clear();
mp['A'] = mp['B'] = mp['C'] = '2';
mp['D'] = mp['E'] = mp['F'] = '3';
mp['G'] = mp['H'] = mp['I'] = '4';
mp['J'] = mp['K'] = mp['L'] = '5';
mp['M'] = mp['N'] = mp['O'] = '6';
mp['P'] = mp['R'] = mp['S'] = '7';
mp['T'] = mp['U'] = mp['V'] = '8';
mp['W'] = mp['X'] = mp['Y'] = '9';
} void cmp(char a[]) {
int len = strlen(a);
char s[maxn];
for(int i = 0; i < len; i++) {
s[i] = mp[a[i]];
}
s[len] = '\0';
if(strcmp(s, num) == 0) {
flag = true;
printf("%s\n", a);
}
} int main() {
#ifdef MARK
freopen("namenum.in", "r", stdin);
freopen("namenum.out", "w", stdout);
#endif // MARK
init();
while(~scanf("%s", num)) {
flag = false; freopen("dict.txt", "r", stdin);
while(~scanf("%s", str)) {
if(strlen(str) != strlen(num)) {
continue;
}
cmp(str);
}
if(!flag) {
printf("NONE\n");
}
}
return 0;
}

USACO Section 1.2 Name That Number 解题报告的更多相关文章

  1. 「USACO 1.3」 Name That Number 解题报告

    \(注意 该篇题解为本人较早时期写的题解 所以会很傻 直接能用map 以string为下标偏偏要绕弯儿 有时间改一改QAQ\) [USACO1.2]Name That Number 题目描述 在威斯康 ...

  2. USACO Section 1.3 Ski Course Design 解题报告

    题目 题目描述 有N座山,每座山都有一个高度,现在由于农夫想避税,所以想把这些山的高度进行一些改变,使得最高的山与最低的山之间的高度差不超过17.每座山最多只能改变一次高度,每次改变高度都会产生一定的 ...

  3. USACO Section 1.1 Friday the Thirteenth 解题报告

    题目 题目描述 黑色星期五是否真的是一件不同寻常的事情?按理来说每个月的13号可能是星期一,或者是星期二...或者是星期天,但是黑色星期五的存在让我们不禁开始猜想,难道每个月的13号刚好是星期五的频率 ...

  4. USACO Section 1.1 Greedy Gift Givers 解题报告

    题目 问题描述 有若干个朋友,朋友之间可以选择互相赠送一些有价值的礼物.一个人可以选择将一部分钱分给若干个朋友,例如某人送给其他两个人钱,总共赠送3元,两个人平均分,原本应该是每人1.5元,但是只能取 ...

  5. USACO Section 1.4 Mother's Milk 解题报告

    题目 题目描述 有三个牛奶桶,三个桶的容积分别是A,B,C,最小为1,最大为20.刚开始只有第三个桶里面装满了牛奶,其余两个桶都是空的.我们现在可以将第三个桶中的牛奶往其他两个桶里面倒一些牛奶,然后还 ...

  6. 【九度OJ】题目1040:Prime Number 解题报告

    [九度OJ]题目1040:Prime Number 解题报告 标签(空格分隔): 九度OJ 原题地址:http://ac.jobdu.com/problem.php?pid=1040 题目描述: Ou ...

  7. 【LeetCode】Largest Number 解题报告

    [LeetCode]Largest Number 解题报告 标签(空格分隔): LeetCode 题目地址:https://leetcode.com/problems/largest-number/# ...

  8. 【LeetCode】306. Additive Number 解题报告(Python)

    [LeetCode]306. Additive Number 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http: ...

  9. USACO Section1.2 Name That Number 解题报告

    namenum解题报告 —— icedream61 博客园(转载请注明出处)-------------------------------------------------------------- ...

随机推荐

  1. 数据结构——求单向链表的倒数第K个节点

    首先,对于链表来说,我们不能像数组一样直接访问,所以我们想到要求倒数第K个节点首先要知道最后一个节点. 然后从最后一个节点往前数K个. 最后得到想要的值. 但是这是不对的,为什么呢?因为题目给出的是单 ...

  2. JRE与JDK

    Java源代码是以*.java的纯文本文件,可以使用任何文本编辑器编写,但不可以执行. JDK是Java语言的开发包,可以将*.java文件编译成可执行Java文件. 可执行Java程序需要JVM才可 ...

  3. .net项目svn项目管理文件清单

    You can add the following files to Visual Studio source control: Solution files (*.sln). Project fil ...

  4. Nginx 和 IIS 实现动静分离【转载】

    前段时间,搞Nginx+IIS的负载均衡,想了解的朋友,可以看这篇文章:<nginx 和 IIS 实现负载均衡>,然后也就顺便研究了Nginx + IIS 实现动静分离.所以,一起总结出来 ...

  5. MySQL-测试卷一

    MySQL-测试卷一 一.单项选择题 1 下面不属于Msql数据库特点的是(  ) A. 免费使用  B.不能跨平台  C.开源软件  D.功能强大 2 定义表的一个字段, 要求能表示4位整数,2位小 ...

  6. 用GDB调试程序的设置 Segmentation fault(Core Dump)调试

    在写wifi库的时候碰见一个 Segmentation fault(Core Dump) 所以需要用GDB调试下. 在cmake的时候,修改CMakeLists.txt set(CMAKE_C_FLA ...

  7. JS-加载页面的时候自动选择刚才所选择option

    <body class="no-skin" onload="option_auto(${pd.PACK_SORT})"> <select na ...

  8. auto_ash

    #!/usr/bin/ksh ##############paramter######################startdate=$1' 00:00:01'enddate=$2' 23:59: ...

  9. 【sort】 基数排序

    下面这段问答摘自csdn: 把基数排序说成桶排序应该是没有太大问题的.总的说来,应该把这一类归为分配排序,由于分配排序的一些缺陷,主要是时间代价很差,改进成为桶式排序(bucket sort),而桶排 ...

  10. OpenGL ES着色器语言之操作数(官方文档第五章)

    OpenGL ES着色器语言之操作数(官方文档第五章) 5.1操作数 OpenGL ES着色器语言包含如下操作符. 5.2数组下标 数组元素通过数组下标操作符([ ])进行访问.这是操作数组的唯一操作 ...