前言
参考大佬博主的思路:https://blog.csdn.net/su_cicada/article/details/78939610
从这题我真的体会到了 “题题平等”,题目短它就简单了吗,题目长它就难了吗?虽然大部分情况下简单的题目是比较短,等下等下,再往下讲我觉得都上升到人生问题了,以上,END。:)
注:本文干货是 题目、思路、AC代码,其他都是废话,对,是的,没错,我就爱说废话,你怎么知道,太聪明了~
题目
UVa原题传送门:https://vjudge.net/problem/UVA-202
输入整数a和b(0<=a<=3000,1<=b<=3000),输出a/b的循环小数表示以及循环节长度。例如a=5,b=43,小数表示为0.(116279069767441860465),循环节长度为21。
思路
首先,你要知道这一点:
所有的分数,要么是有限小数,要么是无限循环小数!!!
接下来,手算一下除法1÷6,(对,就是用小学的除法算法),看看我的丑字,让我给看官娓娓道来,:
我们用除法计算小数部分的过程,简单来说就是在进行不断的乘10取余,当然这里的分数要为真分数(比如7 / 6,我们就单独算整数部分1,剩下的1 / 6才是我们的操作对象,所以刚开始的时候,让分子7对分母6进行一次取余%运算即可)。
把每次乘10取余过程中的被除数、整除结果(即分数部分的值呀)存起来,当出现相同的被除数时,即循环开始了!小数循环体的起点就是当前遍历到的被除数的位置。如上图的1 / 6 起点为1 ,5 / 7 起点为 0 (在数组中下标要减1,vector容器也一样)。
为什么呢?嗯,这个问题嘛,因为想想就是啊,你想哈,当被除数相同,除数也相同,那不就是一样的计算过程了吗,就是不断在循环,一轮一轮的,不信你试试。
证明我可不会,比如你给我证明一下“ 1 + 1 = 2”呀,嘿嘿嘿。
ac代码心路历程
2020/3/11 早
太年轻,看完了UVa上的原题才意识到,我只是知道了一个常识:所有分数均可表示为无限循环小数。
然后其实我上面说的情况只是其中一种,还有1/250(小数部分有前导0),1/6(循环并不是从头开始的情况)。
昨晚我尝试了从局部推整体,想从特殊情况入手,也就是分类一下,直接暴力解题,嗯,以失败告终。
(小声bb:有些数据过了鸭hhhhhh,只能过特例…)
果然,这种从特殊情况入手,接着分类,进行暴力解题,很容易疏漏,且得出的答案并不适用于一般情况。
2020/3/11 晚
看了几篇博客,阅读别人的代码真的好难,还是看不来,但是学到思路了,用被除数来做标识啊,另外在记录循环体开始的头部和长度!哇,帅,我要敲我的2.0,看我的,任意门!!!
hhh,AC了,好开心,经过两天的峰回路转,辗转反侧,终于柳暗花明,给我AC了!!!!!!!
AC代码
/*
UVa202,ACM/ICPC World Finals 1990
2.0
reasonBao
*/
#include <iostream>
#include <vector>
using namespace std;
int main() {
int fenzi, fenmu;
while (cin >> fenzi >> fenmu) {
vector <int> dividement; //记录每一步的被除数
vector <int> decimals; //记录小数部分
int fenzi_beginner = fenzi;
fenzi = fenzi % fenmu; //化为真分数
int cycle_begin = 0, cycle_end = 0;
while (1) {
fenzi = fenzi % fenmu * 10;
bool is_over = false;
for (int i = 0; i < dividement.size(); i++) {
if (dividement[i] == fenzi) {
cycle_begin = i;
is_over = true;
}
}
if (is_over) break;
decimals.push_back(fenzi / fenmu);
dividement.push_back(fenzi);
}
// cout << "dividement length = " << dividement.size() << endl;
// for (int i = 0; i < dividement.size(); i++) cout << dividement[i] << " ";
//
// cout << "\ndecimals length = " << decimals.size() << endl;
// for (int i = 0; i < decimals.size(); i++) cout << decimals[i] << " ";
//
// cout << "\ncycle_begin = " << cycle_begin << endl;
int cycle_length = dividement.size() - cycle_begin;
// cout << "cycle_length = " << cycle_length << endl;
//开始打印结果咯
int count_out = 0;
cout << fenzi_beginner << "/" << fenmu << " = ";
cout << fenzi_beginner / fenmu << ".";
for (int i = 0; i < cycle_begin; i++) {
cout << decimals[i];
count_out++;
}
cout << "(";
for (int i = cycle_begin; i < decimals.size(); i++) {
cout << decimals[i];
count_out++;
if (count_out == 50) {
cout << "...";
break;
}
}
cout << ")";
cout << endl;
cout << " " << cycle_length << " = " << "number of digits in repeating cycle" << endl;
cout << endl;
}
return 0;
}
以下是代码1.0,Failed,蛮记录一下:
/*
UVa202,ACM/ICPC World Finals 1990
*/
#include <iostream>
#include <vector>
using namespace std;
int main() {
int fenzi, fenmu;
while (cin >> fenzi >> fenmu) {
//1. 整除的特殊情况直接处理
if (fenzi % fenmu == 0) {
printf("%d/%d = %d(0)\n", fenzi, fenmu, fenzi/fenmu);
printf(" %d = number of digits in repeating cycle\n", 1);
continue;
}
int begin_fenzi = fenzi;
vector <int> remainder_part;
vector <int> decimal_part;
fenzi %= fenmu; //转化为真分数
int count_zero = 0; //计数,小数部分前面的0的个数
//2. 处理1/250 这类的小数前面0的情况,目标是化为100/250
while (fenzi*10 < fenmu) {
count_zero++;
fenzi *= 10;
}
fenzi *= 10;
while(1) {
bool is_over = false;
decimal_part.push_back(fenzi / fenmu);
for (int i = 0; i < remainder_part.size(); i++) {
if (fenzi % fenmu == remainder_part[i]) {
is_over = true;
}
}
if (is_over) break;
// decimal_part.push_back(fenzi / fenmu);
remainder_part.push_back(fenzi % fenmu);
fenzi = fenzi % fenmu * 10;
}
//开始输出结果
cout << begin_fenzi / fenmu << ".";
for (int i = 0; i < count_zero; i++) cout << "0";
int pos = 0;
for ( ; pos < decimal_part.size() - remainder_part.size(); pos++) {
cout << decimal_part[pos];
}
cout << "(";
for (int i = 0; i < remainder_part.size(); i++) {
cout << decimal_part[i+pos];
}
cout << ")";
}
return 0;
}
进一寸有一寸的欢乐 —— > _ <