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...).
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章