POJ1930,无限循环小数变分数

题意非常好理解,看题就知道,不在详述。

方法如下:
此题主要是推公式,依据循环节推公式:
1.循环节有多少就有几个9,然后用0添齐总位数,这就是分子;
2.然后用整个数减去没有循环节的整数,得到的就是分母;
3.不要问我为什么,我也不造,知识推导而已,小学奥数!!!
4.如0.12312…,若12为循环节,那么分子就是99000,然后分母就是12312 - 123,之后约分得到的就是结果;
5.此题有两坑,1.就是可能出现0.00000…这个数;2.就是题意不清,不知道循环节是多少,所以要枚举循环节;

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>

#define maxn 100010
#define ll long long

using namespace std;

ll ppow(ll a, int b)
{
    ll sum = 1;
    while (b)
    {
        if (b & 1)
            sum *= a;
        a *= a;
        b /= 2;
    }
    return sum;
}

ll gcd(ll a, ll b)
{
    if (!b)
        return a;
    return gcd(b, a % b);
}

int main()
{
    char str[100];
    while (1)
    {
        gets(str);
        if (strlen(str) == 1) break;

        ll sum = 0, x = 1;   //求小数点后的那个整数
        for (int i = strlen(str) - 4; str[i] != '.'; --i)
        {
            sum += (ll)(str[i] - '0') * x;
            x *= 10;
        }

        if (sum == 0)
        {
            printf("0/1\n");
            continue;
        }

        int len = strlen(str) - 5;
        ll ans_1 = 0, ans_2 = 1e15;
        for (int i = 1; i <= len; ++i)  //混循环和纯循环都已算
        {
            ll num_1 = 0, num_2 = 0;
            for (int j = 1; j <= i; ++j)
            {
                num_2 += 9 * ppow((ll)10, len - j);
            }

            num_1 = sum - sum / ppow((ll)10, i);

            ll d = gcd(num_1, num_2);
            num_1 /= d;
            num_2 /= d;
            if (ans_2 > num_2)
            {
                ans_1 = num_1;
                ans_2 = num_2;
            }
        }
        printf("%lld/%lld\n", ans_1, ans_2);
    }

    return 0;
}

你可能感兴趣的:(Math,poj,欧几里得算法,分数,无限循环小数)