《挑战程序设计竞赛》2.6.1 数学问题-辗转相除法 AOJ0005 POJ2429 1930(1)

AOJ0005

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0005

题意

给定两个数,求其最大公约数GCD以及最小公倍数LCM。

思路

求最大公约数一般用辗转相除法,然后就得到了最小公倍数。
更详细的分析参见我的博客文章:
数论——最大公约数和最小公倍数算法

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

unsigned GCD(unsigned a, unsigned b)
{
    if (!b) return a;
    return GCD(b, a%b);
}

unsigned LCM(unsigned a, unsigned b)
{
    return a / GCD(b, a-b) * b;
}

int main(void)
{
    unsigned a, b;
    while (scanf("%u %u", &a, &b) != EOF) {
        if (a < b) swap(a, b);
        printf("%u %u\n", GCD(a, b), LCM(a, b));
    }

    return 0;
}

POJ2429

POJ1930

http://poj.org/problem?id=1930

题意

将一个无限循环小数转化成分母最小的精确分数值。
注意:循环的部分不一定是最后一位,有可能从小数点后面全是循环部分。

思路

将分数分成循环的部分和非循环的部分:
设分数为0.i1 i2 i3 i4 .. ik j1 j2 j3 .. jc,其中i1 ~ ik 为非循环的部分,j1 ~ jc为循环部分。
非循环的部分可以拆成 b / a 其中 b = ( i1…ik) a = 10 ^ (k);
循环的部分可以拆成 bb / aa 其中 bb = (j1 .. jc) aa = 10 ^ (k + c) - 10 ^ ( k);
则所求分数为 b / a + bb / aa,通分得 (b * aa + bb * a) / a * aa,约分得答案(用最大公约数求)。
另外,据说数据会有全是0的坑爹数据,但我没有被坑到。

代码

Source Code

Problem: 1930       User: liangrx06
Memory: 172K        Time: 16MS
Language: C++       Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <algorithm>
using namespace std;

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

int exp10(int x)
{
    int res = 1;
    while (x--)
        res *= 10;
    return res;
}

int main(void)
{
    int i, j, a, b, a10, b10, g, len;
    int m, n;
    string s, sa, sb;

    while(cin >> s)
    {
        if(s == "0")
            break;

        len = s.size();
        for(i = 1; i <= len-5; i++) {
            sa = s.substr(len-3-i, i);
            a = atoi(sa.c_str());
            a10 = exp10(i);

            j = len-5-i;
            sb = s.substr(2, j);
            b = atoi(sb.c_str());
            b10 = exp10(j);

            int tn = (a10-1)*b10;
            int tm = b*(a10-1) + a;
            g = gcd(tn, tm);
            tn /= g;
            tm /= g;
            if (i == 1 || i > 1 && tn < n) {
                n = tn;
                m = tm;
            }
        }
        printf("%d/%d\n", m, n);
    }

    return 0;
}

你可能感兴趣的:(算法,poj,辗转相除法,AOJ,挑战程序设计竞赛)