【PAT乙級】1062 最簡分數
阿新 • • 發佈:2018-12-17
一個分數一般寫成兩個整數相除的形式:N/M,其中 M 不為0。最簡分數是指分子和分母沒有公約數的分數表示形式。
現給定兩個不相等的正分數 N1/M1 和 N2/M2,要求你按從小到大的順序列出它們之間分母為 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;
}
總結
學習不息,繼續加油