[USACO]1.2.3 name that number

原创 2016年08月30日 02:48:46

题目大意

:输入一串数字,根据数字可以导出一大堆名字,要找出所有既能导出,又存在于字典当中的名字。其中2可以代表A,B,C;3代表D,E,F,依此类推,但是字母Q和Z不存在。
键盘分布
其中字典需要单独读入,文件名为dict.txt

首先是正常人的解法

不要被题目骗了
题目叫你通过数字找出所有名字你就通过数字找出所有名字???
那你484撒(对我就是撒

深搜的深度最大为13,需要遍历3^d个搜索树节点。

改变一下策略,反正你要挨个读入字典dict.txt,那还不如反着把字典里头的名字转化成数字代码。
打表:

int map[26]={2,2,2,//ABC
            3,3,3,//DEF
            4,4,4,//GHI
            5,5,5,//JKL
            6,6,6,//MNO
            7,0,7,7,//PQRS,其中Q不存在所以设为0
            8,8,8,9,9,9};

论如何将一个“名字”转化成代码

int transfer(string name){
    int ret=0;
    for(int i=0;i<name.length();i++){
        ret*=10;
        ret+=map[name[i]-'A'];//数据保证大写
    }
    return ret;
}
//main()
FILE *d=fopen("dict.txt","r");
char buffer[30];
while(~fscanf(d,"%s",buffer){
    if(transfer(buffer)==code){
        exist=true;
        cout<<buffer<<endl;
    }
}
if(!exist)cout<<"NONE";

做一个逗逼

我就脑残地建立了两棵字典树+dfs(微笑)虽然时间慢了(每次都要把所有情况算出来)而且空间大了(这不明显么)然而还是过了13组数据(共15组,以wa告终,我错在没有排除Q和Z)我觉得那行吧顺便复习下字典树和dfs,就又写了一遍。(逗逼青年欢乐多)


字典树:

struct node {
    node *child[26];
    bool exist;//记录是否为终结点
    //终结点是我自己起的名字,我并不知道应该叫什么= =
    node() {
        for (int i = 0; i < 26; i++)child[i] = 0;
        exist = 0;
    }
};
class Trie {
    node *root;
public:
    Trie() {
        root = new node;
    }
    void insert(string str) {
        node *scout = root;
        for (int i = 0; i < str.length(); i++) {
            int target = str[i] - 'A';//题目保证全大写
            if (!scout->child[target])scout->child[target] = new node;
            scout = scout->child[target];
        }
        scout->exist = 1;
    }
    friend void compare(Trie&, Trie&);
};

为了题目,我暂时没有写查询函数,因为不需要(废话)
其中compare(Trie &,Trie &) 是用来同时遍历两棵字典树用的。规则如下:

1、对于任意结点,如果a树中存在但b树中不存在,则不访问此节点
2、对于任意节点,如果此节点同时在a、b两棵树中以终结点(从根结点到此节点能够形成一个存在字典中的单词)则输出此节点的单词。

我的trie树节点的特点是,结点本身不存储自己是’a’还是’b’,链接到上一节点的对应位置,这样既可以保证访问速度又可以保证存储空间。

对任意树遍历方法:

void traversal(node *target, string current) {
    for (int i = 0; i < 26; i++)
        if(target->child[i])
            traversal(target->child[i],current+(char)(i+'a'));
    if (target->exist){
        //todo:输出节点信息
        //optional:计数器++
    }
}
/*调用:*/traversal(root,"");

言归正传,现在用这个开始做题
首先实例化两棵字典树all和dict

Trie all,dict;

咱先把那个神奇的数字串dfs一下,把所有可能的名字找出来(逗逼本质暴露的时刻到了)

string key;
void dfsName(int digit, int num, string name) {
    if (digit >= key.length()) {
        all.insert(name);//向其中一棵字典树中插入能打出的所有名字
        return;
    }
    for (int i = 0; i < 3; i++) {
        dfsName(digit + 1, i, name + (char)(i + (key[digit] - '0') * 3 - 6 + 'A'));
        //错就错在这了,这里只适用于'A'到'P'之间的名字。
        //总之我懒得改了
    }
}
//把电话号码读到key里头然后调用:
dfsName(0,0,"");

然后再读取dict.txt…

FILE *dicttxt=fopen("dict.txt","r");
char buffer[30];//13
while(~fscanf(dicttxt,"%s",buffer))dict.insert(buffer);

至此我们有了两棵字典树。接下来我们要做的就是把两颗字典树“重叠”起来,同时遍历,就可以找到所有共有的终结点了。

void compare(node *a, node *b, string current) {
    node *sca = a, *scb = b;
    for (int i = 0; i < 26; i++) {
        if (sca->child[i] && scb->child[i])
            compare(sca->child[i], scb->child[i], current + (char)(i + 'A'));
            //根据遍历策略,我需要走一步,"顺"一个字母。从上到下连起来成为单词
    }
    if (sca->exist&&scb->exist){
            good=true;
            cout << current.c_str() << endl;
        }
}
void compare(Trie &a, Trie &b) {
    compare(a.root, b.root, "");
    //这就是为什么我在trie类中要声明friend void compare (Trie &,Trie &);
}

综上,在这里放一下我ac的代码(成就:放肆的逗逼青年:达成)

#include<iostream>
using namespace std;
struct node {
    node *child[26];
    bool exist;
    node() {
        for (int i = 0; i < 26; i++)child[i] = 0;
        exist = 0;
    }
};
class Trie {
    node *root;
public:
    Trie() {
        root = new node;
    }
    void insert(string str) {
        node *scout = root;
        for (int i = 0; i < str.length(); i++) {
            int target = str[i] - 'A';
            if (!scout->child[target])scout->child[target] = new node;
            scout = scout->child[target];
        }
        scout->exist = 1;
    }
    friend void compare(Trie&, Trie&);
}all, dict;
bool good=0;
void compare(node *a, node *b, string current) {
    node *sca = a, *scb = b;
    for (int i = 0; i < 26; i++) {
        if (sca->child[i] && scb->child[i])
            compare(sca->child[i], scb->child[i], current + (char)(i + 'A'));
    }
    if (sca->exist&&scb->exist){
            good=true;
            cout << current.c_str() << endl;
        }
}
void compare(Trie &a, Trie &b) {
    compare(a.root, b.root, "");
}
string key;
void dfsName(int digit, int num, string name) {
    if (digit >= key.length()) {
        all.insert(name);
        return;
    }
    for (int i = 0; i < 3; i++) {
        char newDigit=(char)(i + (key[digit] - '0') * 3 - 6 + 'A');
        if(newDigit>='Q')newDigit++;
        dfsName(digit + 1, i, name + newDigit);
    }
}
int main() {
    freopen("namenum.in","r",stdin);
    freopen("namenum.out","w",stdout);
    char a[13];
    FILE *diccc=fopen("dict.txt","r");
    while(~fscanf(diccc,"%s",a))dict.insert(a);
    cin >> a;
    key = a;
    dfsName(0, 0, "");
    compare(all, dict);
    if(!good)cout<<"NONE";
}

好的。我觉得没有人会像我这样写这样逗逼的题解。所以我决定继续写下去。

其实,USACO是支持C++11的,也就是说我可以放肆地用STL(standard template library)里的set,不用担心兼容不兼容。所以其产物如下。

#include<set>
using namespace std;
#include<iostream>
set<string> dict;
bool exist=false;
string key;
void dfsName(int digit, int num, string name) {
    if (digit >= key.length()) {
        if(dict.find(name)!=dict.end()){
            exist=true;
            cout<<name<<endl;
        }
        return;
    }
    for (int i = 0; i < 3; i++) {
char newDigit=(char)(i + (key[digit] - '0') * 3 - 6 + 'A');
        if(newDigit>='Q')newDigit++;
        dfsName(digit + 1, i, name+newDigit);}
}
int main(){
    freopen("namenum.in","r",stdin);
    freopen("namenum.out","w",stdout);
    FILE *diccc=fopen("dict.txt","r");
    while(~fscanf(diccc,"%s",a))dict.insert(a);    
    cin>>a;key=a;
    dfsName(0,0,"");
    if(!exist)cout<<"NONE";
}

ac
interesting

版权声明:本文为博主原创文章,爱转转不转算 https://blog.csdn.net/FrankLi101000100/article/details/52364754

Number类

本课程介绍java.lang.Number类 详细介绍了Number类的使用,格式化,精确计算等
  • 2017年02月06日 13:33

usaco 1-2-3 Name That Number

usaco持续更新中 nocow翻译 Name That Number 命名那个数字 目录  [隐藏]  1 描述2 格式3 SAMPLE I...
  • shuiti_ac_ji
  • shuiti_ac_ji
  • 2016-03-05 11:04:50
  • 368

Name That Number命名那个数字

Name That Number命名那个数字 在威斯康辛州牛大农场经营者之中,都习惯于请会计部门用连续数字给母牛打上烙印. 但是,母牛用手机时并没感到这个系统的便利,它们更喜欢用它们喜欢的名字...
  • jie_guale
  • jie_guale
  • 2011-09-09 20:58:01
  • 289

【USACO题库】1.2.3 Name That Number命名那个数字

题目描述 在威斯康辛州牛大农场经营者之中,都习惯于请会计部门用连续数字给母牛打上烙印。 但是,母牛用手机时并没感到这个系统的便利,它们更喜欢用它们喜欢的名字来呼叫它们的同伴,而不是用像这个的语句"...
  • gmh77
  • gmh77
  • 2016-08-15 16:29:12
  • 289

USACO 1.2.3 Name That Number

USACO  1.2.3 Name ThatNumber USACO打不开所以没提交      题意:有好多头奶牛,它们每一头都有一个编号,每个数字分别对应三个字母,每个数字从它对应的字母中挑一个出来...
  • weixinwei021
  • weixinwei021
  • 2013-08-05 23:15:20
  • 560

usaco 1.2.3 name that number

我一定是和文件有仇是吧一定是的。。下一道题回文那个难得做的比较顺(只是比较。。囧- -)而且本机上测得没什么问题,以为一定能一次ac了,结果输出文件的stdout手贱写成了stdin。。。。不过至少是...
  • shshwdr
  • shshwdr
  • 2012-02-13 21:16:46
  • 505

[USACO 1.2.3] Name That Number

[题目描述] Name That Number 命名那个数字 在威斯康辛州牛大农场经营者之中,都习惯于请会计部门用连续数字给母牛打上烙印。 但是,母牛用手机时并没感到这个系统的便利,它们更...
  • zane295384295
  • zane295384295
  • 2011-11-26 18:18:41
  • 217

USACO 1.2.3 Name That Number

/**//*PROG: namenumLANG: C++*/#include iostream>#include fstream>#include string>#include cmath>usin...
  • wind29831
  • wind29831
  • 2007-09-23 19:51:00
  • 333

USACO 1.2.3 Name That Number

思路:先把dict.txt中的名字都转化成数字,存储在数组中,便于查找。需要注意的是数字与字母的对应表里没有字母Q和Z,还有就是如果有多组满足题意,则都需要输出。 代码如下: /* ID:...
  • michaelalan
  • michaelalan
  • 2012-02-21 21:52:08
  • 301

USACO 1.2.3

Name That Number Among the large Wisconsin cattle ranchers, it is customary to brand cows with se...
  • zkzxmzk
  • zkzxmzk
  • 2013-05-15 20:50:23
  • 10242
收藏助手
不良信息举报
您举报文章:[USACO]1.2.3 name that number
举报原因:
原因补充:

(最多只允许输入30个字)