1. 程式人生 > >【PAT乙級】1062 最簡分數

【PAT乙級】1062 最簡分數

一個分數一般寫成兩個整數相除的形式:N/M,其中 M 不為0。最簡分數是指分子和分母沒有公約數的分數表示形式。

現給定兩個不相等的正分數 N​1​​/M​1​​ 和 N​2​​/M​2​​,要求你按從小到大的順序列出它們之間分母為 K 的最簡分數。

輸入格式:

輸入在一行中按 N/M 的格式給出兩個正分數,隨後是一個正整數分母 K,其間以空格分隔。題目保證給出的所有整數都不超過 1000。

輸出格式:

在一行中按 N/M 的格式列出兩個給定分數之間分母為 K 的所有最簡分數,按從小到大的順序,其間以 1 個空格分隔。行首尾不得有多餘空格。題目保證至少有 1 個輸出。

輸入樣例:

7/18 13/20 12

輸出樣例:

5/12 7/12

個人理解

本題有兩種思路。

第一種

這種思路是直接找到最簡分數分子的範圍,通過begin = n1*k/m1 + 1【這個+1我一開始錯誤地處理成只在n1*k%m1 != 0的時候+1,導致第三個測試點一直過不去,後來突然意識到無論什麼時候初始點都要在整除的結果上+1】,end = n2*k/m2【當n2*k) % m2 == 0時需要將end --】。然後直接在這個範圍內進行gcd的檢查即可。

題目中還有一個坑點就是N1/M1和N2/M2的大小不確定。

說明:使用這種思路是因為題目中其實沒有規定是真分數【雖然測試資料都是真分數】,而且比進行遍歷優化了一些【雖然只優化了一點點】。

程式碼實現

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <iostream>
#define ll long long
#define ep 1e-5
#define INF 0x7FFFFFFF

int const maxn = 1005;

using namespace std;

//尋找最大公約數
int gcd(int a, int b) {
    if (b == 0)
        return a;
    a = abs(a);
    b = abs(b);
    return gcd(b, a%b);
}

int main() {
    //初始化
    int n1, m1, n2, m2, k, cnt = 0;

    //輸入
    scanf("%d/%d %d/%d %d", &n1, &m1, &n2, &m2, &k);

    //Calculate
    if (n1*m2 > n2*m1) {
        swap(n1, n2);
        swap(m1, m2);
    }
    
    //找到範圍
    int begin = n1*k/m1 + 1, end = n2*k/m2;
    if ((n2*k) % m2 == 0) {
        end --;
    }

    //在範圍內尋找並輸出
    for (int i = begin; i <= end; i ++) {
        if (gcd(i, k) == 1) {
            if (cnt != 0) cout << " ";
            cout << i << "/" << k;
            cnt ++;
        }
    }
    
    return 0;
}

第二種

這種思路其實就是在真分數的範圍內進行遍歷尋找,滿足gcd == 1的最簡真分數輸出即可。

說明:這種方法是我在第一種想法一直AC不過的時候重寫的,然後AC了,後來不甘心第一種怎麼會出錯,結果可以用來測試,最後通過它找到了第一種思路中的bug。

程式碼實現

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <iostream>
#define ll long long
#define ep 1e-5
#define INF 0x7FFFFFFF

int const maxn = 1005;

using namespace std;

//尋找最大公約數
int gcd(int a, int b) {
    if (b == 0)
        return a;
    a = abs(a);
    b = abs(b);
    return gcd(b, a%b);
}

int main() {
    //初始化
    int n1, m1, n2, m2, k, cnt = 0;

    //輸入
    scanf("%d/%d %d/%d %d", &n1, &m1, &n2, &m2, &k);

    //Calculate
    if (double(1.0*n1/m1) > double(1.0*n2/m2)) {
        swap(n1, n2);
        swap(m1, m2);
    }

    for (int i = 1; i < k; i ++) {
        //下列兩種邊界條件方法都可以,乘法可以避免浮點轉化的問題
        //if (i > 1.0*n1*k/m1 && i < 1.0*n2*k/m2 && gcd(i,k) == 1) {
        if (i*m1 > n1*k && i*m2 < n2*k && gcd(i, k) == 1) {
            if (cnt != 0) cout << " ";
            cout << i << "/" << k;
            cnt ++;
        }
    }
    
    return 0;
}

總結

學習不息,繼續加油