POJ 1930

    一道很有意思的数学题,如果你之前知道方法,那么这题就不难,否则还是挺难得。我网上找了几份解题报告后,只懂过程,不懂原理。唉,先这样吧!
    下面是我转载(http://www.hankcs.com/program/cpp/poj-1930-dead-fraction.html)的解题方法,看完之后大家就差不多明白了。混循环的两个例子很有代表性,一定要都看。

纯循环

用9做分母,有多少个循环数就几个9,比如0.3,3的循环就是9分之3,0.654,654的循环就是999分之654, 0.9,9的循环就是9分之9(1),以此类推。

混循环

先来看几个例子
例:把混循环小数0.228˙化为分数:
解:0.228˙
=[(228/1000)+8/9000)]
=228/(900+100)+8/9000
=[(228/900)-(228/9000)]+(8/9000)
=(228/900)+[(8/9000)-(228/9000)]
=(228/900)-(22/900)
=(228-22)/900
=206/900
=103/450;
例:把混循环小数0.123˙68˙化成分数:
解:0.123˙68˙=(0.12368+0.00000˙68˙)
=(12368/100000)+(68/9900000)
=[(12368/99000)-(12368/990000)]+(68/9900000)
=(12368/99000)+[(68/9900000)-(12368/9900000)]
=(12368/99000)-(12300/9900000)
=(12368-123)/99000

公式
用9和0做分母,首先有几个循环节就几个9,接着有几个没加入循环的数就加几个0,再用小数点后面的数减 没加入循环的数,比如0.43,3的循环,有一位数没加入循环,就在9后面加一个0做分母,再用43减4做分子,得 90分之39,0.145,5的循环就用9后面加2个0做分母,再用145减14做分子,得900分之131,0.549,49的循环,就 用99后面加1个0做分母,用549减5做分子,最后得990分之545,以此类推,能约分的要化简。

    在补充一点,分数转换成的小数有两种类型,一种是有限小数,另一种是无限循环小数(又细分为纯循环和混循环),而有限小数也可以按混合循环的方法来做,此时循环节为“0”,当然纯循环也是按照混循环的方法来做。综上可知,此题考查的就是上述那个方法,不过由于我们并不知道循环节是那个,所以要进行枚举。题目里说by simplest, he means the the one with smallest denominator,也就说明答案是分母最小的那个。题目还要求分数要化简,所以又要用到辗转相除法。
    还要注意的是,题目还会出现0.000…的情况(在题目的discuss部分有人提及)。我在求”9999……“这样的分母时用了pow函数,发现在返回值较大的情况下回出现错误,网上一查才发现pow函数的返回值类型是浮点型,所以最后只好采用循环乘10的方法来构造。


代码(G++):

#include <iostream>
#include <cstdio>
#include <cmath>

#define INF 9999999999
using namespace std;

long long gcd(long long a, long long b)
{
    if(b == 0) return a;
    else return gcd(b, a%b);
}

int main()
{
    string number, cir;
    size_t k, len;
    long long num1, num2, a, b, c, numerator, denominator;

    while(cin>>number && number != "0")
    {
        number = number.substr(2, number.length()-5);
        sscanf(number.c_str(), "%I64d", &num1);
        //cout<<num1<<endl;
        if(num1 == 0)
        {
            cout<<"0/1"<<endl;
            continue;
        }else{
            len = number.length();
            denominator = INF;
            //cout<<denominator<<endl;
            for(k=0; k<len; k++)
            {
                cir = number.substr(k, len-k);
                sscanf(cir.c_str(), "%I64d", &num2);

                a = num2 - num1;
                for(size_t i=0; i<cir.length(); i++) a /= 10;
                a += num1;
                b = 1;
                for(size_t i=0; i<cir.length(); i++) b *= 10;
                b -= 1;
                for(size_t i=0; i<k; i++) b *= 10;
                c = gcd(a, b);
                //cout<<a<<'\t'<<b<<endl;
                a /= c;
                b /= c;
                if(b < denominator)
                {
                    numerator = a;
                    denominator = b;
                }
            }
            cout<<numerator<<'/'<<denominator<<endl;
        }
    }
    return 0;
}

题目
Dead Fraction
Time Limit: 1000MS Memory Limit: 30000K

Description

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).
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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值