挑战程序设计竞赛2.6习题:Dead Fraction POJ - 1930
Mike is frantically scrambling to finish his thesis at the last minute. He needs to assemble all his research notes into vaguely coherent form in the next 3 days. Unfortunately, he notices that he had been extremely sloppy in his calculations. Whenever he needed to perform arithmetic, he just plugged it into a calculator and scribbled down as much of the answer as he felt was relevant. Whenever a repeating fraction was displayed, Mike simply reccorded the first few digits followed by "...". For instance, instead of "1/3" he might have written down "0.3333...". Unfortunately, his results require exact fractions! He doesn't have time to redo every calculation, so he needs you to write a program (and FAST!) to automatically deduce the original fractions.
To make this tenable, he assumes that the original fraction is always the simplest one that produces the given sequence of digits; by simplest, he means the the one with smallest denominator. Also, he assumes that he did not neglect to write down important digits; no digit from the repeating portion of the decimal expansion was left unrecorded (even if this repeating portion was all zeroes).
To make this tenable, he assumes that the original fraction is always the simplest one that produces the given sequence of digits; by simplest, he means the the one with smallest denominator. Also, he assumes that he did not neglect to write down important digits; no digit from the repeating portion of the decimal expansion was left unrecorded (even if this repeating portion was all zeroes).
Input
There are several test cases. For each test case there is one line of input of the form "0.dddd..." where dddd is a string of 1 to 9 digits, not all zero. A line containing 0 follows the last case.
Output
For each case, output the original fraction.
Sample Input
0.2... 0.20... 0.474612399... 0
Sample Output
2/9 1/5 1186531/2500000
Hint
Note that an exact decimal fraction has two repeating expansions (e.g. 1/5 = 0.2000... = 0.19999...).
这道题坑点就在于,它实际上是没有给出循环节的,例如0.1234123...实际上循环的是4123,你可能认为循环3或者3412,但是不是,因为题目说了 Mike simply reccorded the first few digits followed by "...".(迈克简单地记录了前几个数字,后跟“ ...”)。所以这道题最好的办法就是暴力查找每一种循环的可能性。
说到具体做法,我们这样看,假设0.1234123...为ans,如果只循环3, 那么ans*107=1234123.333...,而ans*10(7 - 1)=123412.3333...,那么ans*(107 - 106) = 1234123.333... - 123412.333...=1234123-123412,而这个数一定是整数,那么我们假设这个数为X,则ans = X / (107 - 107-1)两个数都是整数,而且能精确的表示该ans的值,我们只要求出两者的GCD即可化简,并且两者均为整数!!!
同理如果循环的是0.12341232323...,那么就是ans = X / (107 - 107-2),只要满足分母约分后是所有可能情况的最小,那么他就是答案,因为题目中有如下假定:he means the the one with smallest denominator(他的意思是最小分母的那个)。
#include <stdio.h> #include <vector> #include <string> #include <iostream> #include <algorithm> #include <string.h> using namespace std; const int INF = 0x3fffffff; char a[20];//读一行 int a_size;//一行的个数 int x, y;//分子分母 int num, change;//例如0.1234123...,当循环3333...时,num = 1234123.333... ,change = 123412.333... int main(void) { while(cin.getline(a, 20)) { int minx, miny;//最小的分母以及此时分子的值 num = 0; miny = INF;//初始化最大 int y1, y2;//在01234.123...中,若循环节是333..,则y1=10^7(1234123一共7位),而y2 = 10^6 (因为7 - 1 = 6(1是因为只循环最后一位) y1 = y2 = 1; a_size = strlen(a); if(a_size == 1) break; a_size -= 3;//剪掉最后三个'...' for(int i = 2; i < a_size; i++)//从0.1234123...的最开始的1开始一直到最后一个3结束,也就是算num的值,y1是10^num的个数) { num = num * 10 + a[i] - '0'; y1 *= 10; y2 *= 10; } change = num;//初始化change a_size -= 2;//去掉字符串的”0.“,此时a_size的值就是num的个数 for(int i = 1; i <= a_size; i++) { change /= 10; x = num - change;//X的值 y2 /= 10; y = y1 - y2;//分母,y2一开始等于y1,每次/=10,就相当于循环节从0个开始逐一递增 int k = __gcd(x, y); if(y / k < miny) { miny = y / k; minx = x / k; } } printf("%d/%d\n", minx, miny); } return 0; }