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;
}