题目如下
一个分数一般写成两个整数相除的形式:N/M,其中 M 不为0。最简分数是指分子和分母没有公约数的分数表示形式。
现给定两个不相等的正分数 N1 /M1 和 N2 /M2,要求你按从小到大的顺序列出它们之间分母为 K 的最简分数。
输入格式:
输入在一行中按 N/M 的格式给出两个正分数,随后是一个正整数分母 K,其间以空格分隔。题目保证给出的所有整数都不超过 1000。
输出格式:
在一行中按 N/M 的格式列出两个给定分数之间分母为 K 的所有最简分数,按从小到大的顺序,其间以 1 个空格分隔。行首尾不得有多余空格。题目保证至少有 1 个输出。
输入样例:
7/18 13/20 12
解题思路
用scanf函数控制输入格式还是一个挺好的选择,这样可以分别得到N1,M1,N2,M2。题目的关键在于使用gcd(最大公约数)和lcm(最小公倍数),代码很简单,利用辗转相除方法可以得到gcd,然后利用gcd又可以实现lcm,代码如下;
int gcd(int a, int b) // 辗转相除法求最大公约数
{
if(a%b==0)
return b;
else
return gcd(b,a%b);
}
int lcm(int a, int b) // 利用gcd求最小公倍数
{
return a/gcd(a,b)*b;
}
获取最小公倍数之后,可以求出M1,M2,K三个数的最小公倍数(两次lcm即可,先求出前两个数的最小公倍数,再和K继续求最小公倍数得到三个数的最小公倍数),这样就可以确定一个分子的范围,通过同分分子乘以相同的乘数得到一个取值范围,再利用循环进行判断是否原始数字与K的最大公约数是否为1,如果是则输出,否则继续循环判断。
代码如下
#include<iostream>
using namespace std;
int gcd(int a, int b) // 辗转相除法求最大公约数
{
if(a%b==0)
return b;
else
return gcd(b,a%b);
}
int lcm(int a, int b) // 利用gcd求最小公倍数
{
return a/gcd(a,b)*b;
}
int main()
{
int N1,M1,N2,M2,K;
scanf("%d/%d %d/%d %d",&N1,&M1,&N2,&M2,&K); // 控制输入格式
int denominator=lcm(lcm(M1,M2),K); // 得到三个数的最小公倍数
N1=denominator/M1*N1; // 得到通分后的N1
N2=denominator/M2*N2; // 得到通分后的N2
// cout<<N1<<"/"<<denominator<<" "<<N2<<"/"<<denominator<<endl;
int flag=denominator/K; // 得到通分后扩大的倍数
// cout<<flag<<endl;
if(N1>N2) // 始终让N1<N2,后文做循环
{
int temp=N1;
N1=N2;
N2=temp;
}
// cout<<N1<<N2<<endl;
int count=0; // 用来计数,控制输出的格式,不然最后测试点过不了
for(int i=N1+1;i<N2;i++) // 循环的范围再N1和N2保证输出的数在两个数之间
{
// cout<<i<<endl;
if(i%flag==0) // 如果能够被扩大的倍数整除说明能化为整数/K的形式
{
if(gcd(K,i/flag)==1) // 如果原始数据与K的最大公约数为1表示最简分数
{
if(count==0) // 如果是第一个输出不带空格
{
cout<<i/flag<<"/"<<K;
count++;
}
else
{
cout<<" "<<i/flag<<"/"<<K;
count++;
}
}
}
}
}