“蓝桥杯”练习系统 BASIC-20 VIP试题 数的读法 | 数字转换拼音

BASIC-20 VIP试题 数的读法

问题描述

Tom教授正在给研究生讲授一门关于基因的课程,有一件事情让他颇为头疼:一条染色体上有成千上万个碱基对,它们从0开始编号,到几百万,几千万,甚至上亿。
  比如说,在对学生讲解第1234567009号位置上的碱基时,光看着数字是很难准确的念出来的。
  所以,他迫切地需要一个系统,然后当他输入12 3456 7009时,会给出相应的念法:   十二亿三千四百五十六万七千零九
  用汉语拼音表示为   shi er yi san qian si bai wu shi liu wan qi qian ling jiu
  这样他只需要照着念就可以了。
  你的任务是帮他设计这样一个系统:给定一个阿拉伯数字串,你帮他按照中文读写的规范转为汉语拼音字串,相邻的两个音节用一个空格符格开。
  注意必须严格按照规范,比如说“10010”读作“yi wan ling yi shi”而不是“yi wan ling
shi”,“100000”读作“shi wan”而不是“yi shi wan”,“2000”读作“er qian”而不是“liang
qian”。

输入格式

有一个数字串,数值大小不超过2,000,000,000。

输出格式

是一个由小写英文字母,逗号和空格组成的字符串,表示该数的英文读法。


事后总结:

蓝桥杯的这种复杂题一定不能慌。不是有多少难度,就是看能不能尽量少花费时间。思路要找准,想好了再动手,写的尽量清楚,不然调试修改都是自己的。

思路:

10000以下的数字读法是相同的。把这种读法写成一个函数 read() 。大于10000(4位)而小于1亿(8位),在标准 read() 之后再读出 “万” ,大于1亿(8位)的部分为 read() + “亿” 。输入数据不超过20亿。
因此,我们把输入数据作为字符串读入,并右起按照4位一组分割成子串,不足4位的补齐4位。
对于标准读法 read() 如果出现数字 0 的,需要特别考虑。

  1. 0 出现在整个大数的开头,也就是我们补齐的0,不读;
  2. 出现在一个4位子串,即 read() 的末尾,不读;
  3. 出现在4位子串的前部、中部,无论连续出现几个 0 只读一次。

对于上 1. ,我们用全局变量 bool is_head 记录我们是否在大数的开头。对于 2. 3. ,我们采取在每次 read() 当中维护一个 bool is_preZero 的策略,记录上一个遇见的数位上是否为 0 ,且仅当 read() 读到一个“非零位”时,读出一次 0

特别的,当大数以一次 read() 的十位数字 1 起头时(is_head = true),e.g. 10 0000 , 10 0000 0000 , 读作“十万,十亿”,而非“一十万,一十亿”。

作为输出的严谨性,我们控制行末不要输出额外的空格,采用前置空格分隔。对于 is_head = true 时的第一次输出,不输出空格。

由于练习系统暂不支持C++11,最终版本有一定修改。

AC代码:
// 数字の読み方  <2e10
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
string b[] = {"ling", "yi", "er", "san", "si", "wu", "liu", "qi", "ba", "jiu", "shi"};
string p[] = {" qian", " bai", " shi", ""};	// 前置空格,个位不输出
string r[3];
bool is_head = true;
void read(string s, int flag) {
    if (s.empty())
        return;
    while (s.length() < 4) {	// 补齐
        s = '0' + s;
    }
    // cout << s;
    bool is_pre0 = false;
    for (int i=0; i<4; ++i) {
        char ch = s[i];
        if (ch != '0') {
            if (is_pre0 && !is_head)	// 读 '0'
                cout << ' ' << b[0];
            if (is_head && i == 2 && ch == '1') {	// 大数以十位'1'开头
                if (!is_head) cout << ' ';
                cout << "shi";
            }
            else {
                if (!is_head) cout << ' ';
                cout << b[ch - '0'] << p[i];
            }
            is_pre0 = false;
            is_head = false;
        }
        else
            is_pre0 = true;
    }
    switch (flag)
    {
    case 2:
        cout << " yi";
        break;
    case 1:
        cout << " wan";
        break;
    case 0:
        break;    
    default:
        break;
    }
}
int main() {
    string num;
    cin >> num;
    int n = num.size();
    // 按4位切割
    // 伪代码 思路 (其实是调试失败)
    // string t;
    // for (int i=0; i<n; ++i) {    //tranc by yy-wwwww-gggg
    //     t += num[n - i - 1];
    //     if ((i + 1) % 4 == 0) {
    //         reverse(t.begin(), t.end());
    //         r[i / 4] = t;
    //         t = "";
    //     }
    // }

    // C++ 11
    // for (int i=0; i<3; ++i) {       // r[i]
    //     string t;
    //     for (int j=0; j<4; ++j) {   // r[i][j]
    //         if (num.empty())
    //             break;
    //         t += *num.rbegin();
    //         num.pop_back();
    //     }
    //     reverse(t.begin(), t.end());
    //     r[i] = t;
    //     if (t.length() < 4) break;
    // }

    // Before C++11
    string::reverse_iterator rit = num.rbegin();
    for (int i=0; i<3; ++i) {       // r[i]
        string t;
        for (int j=0; j<4; ++j) {   // r[i][j]
            if (rit == num.rend())
                break;
            t += *rit;
            ++rit;
        }
        reverse(t.begin(), t.end());
        r[i] = t;
        if (t.length() < 4) break;
    }
    // for (int i=2; i>=0; --i) {
    //     cout << r[i] << endl;
    // }
    read(r[2], 2);
    read(r[1], 1);
    read(r[0], 0);
    cout << endl;
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值