USACO Name That Number

本文介绍了一种将电话按键输入转换为对应名字的程序实现方案。通过读取字典文件和电话号码输入,该程序能够查找并输出所有匹配的名字。文章提供了两种方法:一种是通过生成所有可能的字符串进行比对;另一种则是直接检查字典中的每个单词是否匹配电话号码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、这道题刚开始看到要从文件读入“字典”,有点心虚,其实比较简单。

2、思路就是暴力枚举~刚开始我想枚举数字或字母,比较麻烦,后来借鉴了USACO上面讲解的某道IOI题目的思路,换了枚举对象,变成枚举单词(因为题目说了不到5000个),程序一下变得很容易。

/*
ID:mrxy564
PROG:namenum
LANG:C++
*/
#include<cstdio>
#include<map>
#include<cstring>
using namespace std;
map<char,int> a;
int main()
{
    char dic[5000][15];
    a['A']=2;a['B']=2;a['C']=2;
    a['D']=3;a['E']=3;a['F']=3;
    a['G']=4;a['H']=4;a['I']=4;
    a['J']=5;a['K']=5;a['L']=5;
    a['M']=6;a['N']=6;a['O']=6;
    a['P']=7;a['R']=7;a['S']=7;
    a['T']=8;a['U']=8;a['V']=8;
    a['W']=9;a['X']=9;a['Y']=9;
    freopen("namenum.in","r",stdin);
    freopen("namenum.out","w",stdout);
    FILE *fin;
    fin=fopen("dict.txt","rb");
    int i=0,cnt;
    while(fscanf(fin,"%s",dic[i])==1) i++;
    cnt=i;
    fclose(fin);
    long long num;
    char s[15];
    while(scanf("%lld",&num)==1){
         sprintf(s,"%lld",num);
         int len=strlen(s);
         bool flag,judge=false;
         for(int i=0;i<cnt;i++){
            flag=true;
         for(int j=0;j<len;j++)
             if((s[j]-'0')!=a[dic[i][j]]){
                 flag=false;
                 break;
             }
             if(flag&&dic[i][len]=='\0'){
               printf("%s\n",dic[i]);
               judge=true;
             }
          }
          if(!judge) printf("NONE\n");
    }
    return 0;
}
官方题解:

There are two ways to do this problem. One is, given the number, to generate all possible strings that encode to that number and look them up in the dictionary. Since there are 3 letters for each number and 12 digits in the string, that's 312 = 531441 lookups into a dictionary of size 5000, which although manageable would be a little on the long side (binary search can help this).

Or, we can examine each word in the dictionary to see if it maps to the digits of the number in question. This has the the advantage of a shorter program that probably will work right first time.


 

Here is Argentina competitor's Michel Mizrah's solution using the first method with a binary search. While it is blazingly fast, it does have the disadvantage of some fairly tricky coding in the binary search routine. A single off-by-one error would doom a program in a contest.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char num[12],sol[12];
char dict[5000][13];
int nsolutions = 0;
int nwords;
int maxlen;
FILE *out;

void calc (int charloc, int low, int high) {
    if (charloc == maxlen) {
        sol[charloc] = '\0';
        for (int x = low; x < high; x++) {
            if (strcmp (sol, dict[x]) == 0) {
                fprintf (out, "%s\n", sol);
                nsolutions++;
            }
        }
        return;
   }
   if (charloc > 0) {
        for (int j=low; j <= high; j++){
            if (sol[charloc-1] == dict[j][charloc-1]) {
                low=j;
                while (sol[charloc-1] == dict[j][charloc-1])
                    j++;
                high=j;
                break;
            }
            if (j == high) return;
        }
    }
    if (low > high) return;
    switch(num[charloc]){
      case '2':sol[charloc] = 'A'; calc(charloc+1,low,high);
               sol[charloc] = 'B'; calc(charloc+1,low,high);
               sol[charloc] = 'C'; calc(charloc+1,low,high);
               break; 
      case '3':sol[charloc] = 'D'; calc(charloc+1,low,high);
               sol[charloc] = 'E'; calc(charloc+1,low,high);
               sol[charloc] = 'F'; calc(charloc+1,low,high);
               break; 
      case '4':sol[charloc] = 'G'; calc(charloc+1,low,high);
               sol[charloc] = 'H'; calc(charloc+1,low,high);
               sol[charloc] = 'I'; calc(charloc+1,low,high);
               break; 
      case '5':sol[charloc] = 'J'; calc(charloc+1,low,high);
               sol[charloc] = 'K'; calc(charloc+1,low,high);
               sol[charloc] = 'L'; calc(charloc+1,low,high);
               break; 
      case '6':sol[charloc] = 'M'; calc(charloc+1,low,high);
               sol[charloc] = 'N'; calc(charloc+1,low,high);
               sol[charloc] = 'O'; calc(charloc+1,low,high);
               break; 
      case '7':sol[charloc] = 'P'; calc(charloc+1,low,high);
               sol[charloc] = 'R'; calc(charloc+1,low,high);
               sol[charloc] = 'S'; calc(charloc+1,low,high);
               break; 
      case '8':sol[charloc] = 'T'; calc(charloc+1,low,high);
               sol[charloc] = 'U'; calc(charloc+1,low,high);
               sol[charloc] = 'V'; calc(charloc+1,low,high);
               break; 
      case '9':sol[charloc] = 'W'; calc(charloc+1,low,high);
               sol[charloc] = 'X'; calc(charloc+1,low,high);
               sol[charloc] = 'Y'; calc(charloc+1,low,high);
               break;
   }
}

int main(){
    FILE *in=fopen ("namenum.in", "r");
    FILE *in2=fopen ("dict.txt", "r");
    int j;
    out=fopen ("namenum.out","w");
    for (nwords = 0; fscanf (in2, "%s", &dict[nwords++]) != EOF; )
        ;
    fscanf (in, "%s",&num);
    maxlen = strlen(num);
    calc (0, 0, nwords);
    if (nsolutions == 0) fprintf(out,"NONE\n");
    return 0;
}

 

The solution below might be considered to be a bit more straightforward: no tricky offsets, no +1 or -1, no knowledge about character values. The lines of actual code in this solution are minimal.

This is the sort of program that might work reliably the first time and every time. The only tricky part is knowing that scanf will yield string without a newline on the end:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    FILE *in = fopen ("namenum.in", "r");
    FILE *in2 = fopen ("dict.txt", "r");
    FILE *out = fopen ("namenum.out","w");
    int nsolutions = 0;
    int numlen;
    char word[80], num[80], *p, *q, map[256];
    int i, j;
    map['A'] = map['B'] = map['C'] = '2';
    map['D'] = map['E'] = map['F'] = '3';
    map['G'] = map['H'] = map['I'] = '4';
    map['J'] = map['K'] = map['L'] = '5';
    map['M'] = map['N'] = map['O'] = '6';
    map['P'] = map['R'] = map['S'] = '7';
    map['T'] = map['U'] = map['V'] = '8';
    map['W'] = map['X'] = map['Y'] = '9';
    fscanf (in, "%s",num);
    numlen = strlen(num);
    while (fscanf (in2, "%s", word) != EOF) {
        for (p=word, q=num; *p && *q; p++, q++) {
            if (map[*p] != *q)
                break;
        }
        if (*p == '\0' && *q == '\0') {
            fprintf (out, "%s\n", word);
            nsolutions++;
        }
    }
    if (nsolutions == 0) fprintf(out,"NONE\n");
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值