USACO_CHA1_序号命名

一、题目描述

链接https://www.acwing.com/activity/content/problem/content/3069/1/
来源:ACwing

威斯康星州的大型牧场的主人们喜欢用连续的数字编号给奶牛们命名。

但是奶牛们并不喜欢这种看似非常方便的命名方式。

它们希望能够用它们喜欢的名字来互相称呼,而不是像这样“交个朋友吧,4734”。

现在,请你帮助可怜的牧牛人将这些奶牛的编号转换为一个与其编号有所关联的名字。

因为这些奶牛们都配有电话座机,因此请使用如下所示的电话的标准按键映射,来将数字转换为可能的字母(注意,没有 Q 和 Z):

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

现在,我们统计了一个牛可以接受的名字列表,列表中共有不到 5000 个奶牛可以接受的名字。

对于一个拥有某个编号的奶牛,它的编号通过数字与字母的映射,可以得到若干个可能的名字,请你找出这些名字中,奶牛可以接受的名字(即在名字列表中的名字)。

例如,编号 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

我们可以从这些名字中,找到在名字列表中出现过的名字,并字典顺序输出即可。

输入格式
第一行包含一个数字编号,编号的可能长度为 1∼12。

接下来若干行,每行包含一个由大写字母构成的字符串,表示可接受名字名单中的一个名字。

数据保证,这些名字都是按照字典序排列的。

输出格式
输出数字编号对应的所有名字中,在名单中出现过的名字。

注意,按照字典顺序输出,每个名字占一行。

如果没有对应名字,请输出 NONE。

数据范围
数据保证名单中的名字不超过5000个。
奶牛编号中不会出现 1 和 0。

输入样例

4734
ABCD
GREG
XYZ

输出样例

GREG

二、题解

题目理解:
每个数字都对应了三个字母,给了我们一个编号和一堆名字。问能和所给编号匹配的名字有哪些。

解题思路

1、根据编号找名字
我们可以将所给编号对饮的所有名字遍历一遍。然后一一将其与所给名字比对,有匹配的就输出。

编号最长12位,每位对应3个字符,共有3^12种名字。如果是通过遍历所给名字的方法匹配的话,会超时。如果将所给名字用map存的话,不会超时。

但还是不推荐这种方法,因为复杂度相较根据名字匹配编号高。

2、根据名字匹配编号
将所给名字的每个字符找到其对应的数字,看看与所给编号的对应位置的数字是否匹配。所有位数均匹配,则输出;否则,检查下一个名字。

最多有5000个名字,每个编号最多12位,所以这种方法最多需要运算6000次,复杂度完全够用。

数字对应字符
最粗暴的方法就是一共有8个数字,设置8个if语句。
也可以按照我写的代码的方法,可以少些一点儿代码,两个差距不大。

三、AC代码

#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 5005;
string name[maxn];
string num;
bool flag;
bool match(char Al,char Nu);
int main()
{
    cin >> num;
    int i;
    for (i = 0; cin >> name[i] ; i++);
    
    int NameNum = i;
    int NumLen = num.size();
    for ( i = 0; i < NameNum; i++)
    {
        if (name[i].size() != NumLen)
        {
            continue;
        }
        
        int j;
        for (j = 0; j < NumLen; j++)
        {
            if (!match(name[i][j],num[j]))
            {
                break;
            }
        }
        if (j == NumLen)
        {
            cout << name[i] << endl;
            flag = true;
        }
    }

    if (!flag)
    {
        cout << "NONE";
    }
    
    system("pause");
    return 0;
}

bool match(char Al,char Nu)
{
    if (Nu <= '6' && (Al - 'A')/3 == (Nu - '2'))
    {
        return true;
    }
    else if (Nu == '7')
    {
        if (Al == 'P' || Al == 'R' || Al == 'S')
        {
            return true;
        }
        
    }
    else if (Nu >= '8' && (Al - 'A' - 1)/3 == (Nu - '2'))
    {
        return true;
    }
    return false;
}

如果该题解对您有帮助,还望您不吝点赞。
欢迎讨论交流,期待共同进步!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值