1082 Read Number in Chinese (25 分)(C++)

Given an integer with no more than 9 digits, you are supposed to read it in the traditional Chinese way. Output Fu first if it is negative. For example, -123456789 is read as Fu yi Yi er Qian san Bai si Shi wu Wan liu Qian qi Bai ba Shi jiu. Note: zero (ling) must be handled correctly according to the Chinese tradition. For example, 100800 is yi Shi Wan ling ba Bai.

Input Specification:

Each input file contains one test case, which gives an integer with no more than 9 digits.

Output Specification:

For each test case, print in a line the Chinese way of reading the number. The characters are separated by a space and there must be no extra space at the end of the line.

Sample Input 1:

-123456789

Sample Output 1:

Fu yi Yi er Qian san Bai si Shi wu Wan liu Qian qi Bai ba Shi jiu

Sample Input 2:

100800

Sample Output 2:

yi Shi Wan ling ba Bai

题目大意:将一串数字字符串用中文口语的方式读出来。

解题思路:这种类型的模拟题都挺麻烦的emmmm

方法一:

问题一:格式的处理:最后一个字符串后面不能有空格,以往我的处理方式是第一个不输出空格,后面的前面先输出空格,但是这次要是讨论起来会很麻烦,所以干脆每个字符串后面都加上空格,最后输出的时候去掉总字符串的最后一位即可。

问题二:分而治之:既然中文的读法是四个四个地读,要是想分开运算,也肯定是要按照中文数字的分法进行分段,就不难有每一段的处理方式类似,那么就编写一个readpart的函数,即把每一段读出来。

问题三:零的处理方式,这题的最麻烦的地方,分三种情况。

首部的0:碍事...非常碍事,直接去掉,而且很方便接下来的分段,特别是处理超过1亿的数字。不过因此就需要补充处理后字符串长度为0的情况

readpart函数中的0:先不妨假设现在要读的是原字符串的最低四位,这个0可能读,可能不读,像0001(读一个0),1000(一个不读),1001(读一个0);也是三种情况,前面的0,中间的0,后边的0。只要0串(注意是0串!!!)的后面还有非0的数,就把该串读一个0,既然如此,就用flag标记前面是否是0串。

两个part之间:主要是万的4位与个的四位之间,这里又有三种情况:10001111(在readpart中,该0串没有读,所以需要读一个0);10000001(在readpart中,前3个0的串没有读,但是后三个0的串读了一个,所以不需要读);11110001(在readpart中已读,不需要再读)。好了也就是说,我们只需考虑万位后面有0串,个位前面没有0串这一种情况。

#include <iostream>
#include <string>
using namespace std;
string num[11] = {"ling ","yi ","er ","san ","si ","wu ","liu ","qi ","ba ","jiu "};
string book[6] = {"","Shi ","Bai ","Qian ","Wan ","Yi "};
string s,ans;
void readpart(string temp,int len){
    bool flag = false;
    for(int i = 0; i < len; i++){
        if(temp[i] != '0'){
            if(flag == true)
                ans += num[0];
            ans += num[temp[i]-'0'];
            if(i < len-1)  
                ans += book[len-i-1];
            flag = false;
        }
        else
            flag = true;
    }
}
int main(){
    cin>>s;
    if(s[0] == '-')
        ans += "Fu ";
    while(*s.begin() == '0' || *s.begin() == '-')
        s.erase(s.begin());
    int len = s.length(),i = 0;
    if(len > 8)
        ans += num[s[i++]-'0']+book[5];
    if(len > 4){
        int x = min(4,len-4);
        string temp = s.substr(i,x);
        readpart(temp,x);
        i += x;
        ans += book[4];
    }
    if(len > 0){
        int x = min(4,len);
        string temp = s.substr(i,x);
        if(len > 4 && s[i] != '0' && s[i-1] == '0')
            ans += num[0];
        readpart(temp,x);
    }
    if(len == 0)
        ans += num[0];
    ans.pop_back();
    cout<<ans;
}

方法二

刷其他题库的时候遇到类似的题,发现其实代码可以更简洁一些,至少考虑0问题不用像上面这么考虑.

问题一:格式的处理:与方法一相同

问题二:千、百、十...这些东西的读法,设一个pos数组,存放每一位应该读的音,遍历的时候按位遍历,加上数组读法的同时加上pos的读法。

问题三:0问题,在遍历过程中,是用数组取余实现的,比方说1008,读千位然后对1000取余,只有8,所以我们在取余之前判断一下取余之后是不是越过了某些位,如果是的话,就读一个0。

这种方法的好处就是以后如果要扩充的话(读更多位数),是很方便的。

#include <bits/stdc++.h>
using namespace std;
int main() {
    int input, temp, cnt = 0;
    string ans = "";
    scanf("%d", &input);
    string num[] = { "ling ","yi ","er ","san ","si ","wu ","liu ","qi ","ba ","jiu " };
    string pos[] = {"","Shi ","Bai ","Qian ","Wan ","Shi ","Bai ","Qian ","Yi "};
    if (input == 0) 
        ans = num[0]; 
    else {
        if (input < 0) printf("Fu ");
        input = abs(input), temp = input;
        while(temp){
            ++ cnt;
            temp /= 10;
        }
        for(int i = cnt-1; input && i >= 0; -- i){
            int mask = 1;
            for(int j = 0; j < i; ++ j) 
                mask *= 10;
            ans += num[input/mask] + pos[i];
            temp = input%mask;
            if(temp && temp*10 < mask){
                while(temp*10 < mask){
                    -- i;
                    if(i == 4 || i == 8)
                        ans += pos[i];
                    temp *= 10;
                }
                ans += num[0];
            }
            input %= mask;
        }
    }
    ans.pop_back();
    cout << ans;
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值