- 问题描述
写一个程序,输入一个形如N/D的分数(N是分子,D是分母),输出它的小数形式。
如果小数有循环节的话,把循环节放在一对圆括号中。
例如, 1/3 = .33333333 写成0.(3)
41/333 = 0.123123123... 写成0.(123)
用xxx.0 表示整数
典型的转化例子: 1/3 = 0.(3)
22/5 = 4.4
1/7 = 0.(142857)
2/2 = 1.0
3/8 = 0.375
45/56 = 0.803(571428)
- 输入说明
单独的一行包括被空格分开的 N和D, 1 <= N,D <= 100000。 - 输出说明
小数的表示方法上面说的很明白了,如果输出的长度超过76个字符,每行输出76个字符(包括小数点、括号等)。 - 输入范例
cpp
45 56
- 输出范例
cpp
0.803(571428)
感想:用哈希表记录余数数字的位置,一旦再碰到同样的余数,记录下该位置,方便之后加括号。
代码如下:
cpp
#include <bits/stdc++.h>
using namespace std;
void output_decimal(int n,int d) {
string res;
string int_part;
int_part = to_string(n/d);
int remainder = n%d;
res = int_part+".";
vector<char>decimal_digits;
unordered_map<int, int> remainder_pos; // 余数→小数位的位置(记录首次出现位置)
int repeat_pos = -1; // 循环节起始位置(-1表示无循环)
while (remainder != 0) {
// 检查余数是否已出现(检测循环节)
if (remainder_pos.find(remainder) != remainder_pos.end()) {
repeat_pos = remainder_pos[remainder]; // 循环节起始位置
break;
}
remainder_pos[remainder] = decimal_digits.size(); // 记录当前余数的位置
remainder *= 10;
int digit = remainder / d;
decimal_digits.push_back('0' + digit);
remainder = remainder % d;
}
for (int i = 0; i < decimal_digits.size(); ++i) {
// 循环节起始位置,添加左括号
if (i == repeat_pos) {
res += "(";
}
res += decimal_digits[i];
}
// 有循环节则添加右括号
if (repeat_pos != -1)
res += ")";
// 无小数位(余数为0且无循环),补充.0(如2/2=1.0)
else if (decimal_digits.empty()) {
res += "0";
}
int cnt = 0;
for(size_t i=0; i<res.size(); ++i) {
++cnt;
if(cnt%76 == 0) {
cout<<res[i];
cout<<endl;
} else
cout<<res[i];
}
}
//Tips:所有分数(有理数)的小数形式只能是 "有限小数" 或 "无限循环小数",不存在无限不循环的分数
//Tips:无限不循环小数(如 π、√2)是无理数,无法表示为两个整数的比值
int main() {
int n,d;
cin>>n>>d;
output_decimal(n,d);
return 0;
}