一、引例 - 牛客网OJ题
为了更好地说明这个问题,我们以一道牛客网的题目作引例。题目链接贴在这里
题干如下:
当我们提到最大公因数和最小公倍数时,不得不提及的一个重要数学概念就是公倍数和公因数,那么究竟什么是公倍数与公因数呢?今天就让我们揭开它神秘的面纱,看一看他的庐山真面目,来浅显的了解一下他们的概念。
二、公因数与公倍数的概念
公因数
简介
公因数,亦称“公约数”。它是一个能同时整除若干整数的整数 [1]。如果一个整数同时是几个整数的因数,称这个整数为它们的“公因数”;公因数中最大的称为最大公因数。
对任意的若干个正整数,1总是它们的公因数。
释义
给定若干个整数,如果有一个(些)数是它们共同的因数,那么这个(些)数就叫做它们的公因数。而全部公因数中最大的那个,称为这些整数的最大公因数。
公约数与公倍数相反,就是既是A的约数同时也是B的约数的数,12和15的公约数有1,3,最大公约数就是3。再举个例子,30和40,它们的公约数有1,2,5,10,最大公约数是10。
公因数,又称公约数。在数论的叙述中,如果n和d都是整数,而且存在某个整数c,使得n = cd,就说d是n的一个因数,或说n是d的一个倍数,记作d|n(读作d整除n)。如果d|a且d|b,我们就称d是a和b的一个公因数。根据裴蜀定理,对每一对整数a,b,都有一个公因数d,使得d = ax+by,其中x和y是某些整数,并且a和b的每一个公因数都能整除这个d。于是d的绝对值叫做最大公因数。
求几个整数的最大公因数,只要把它们的所有共有的质因数连乘,所得的积就是它们的最大公因数
详情见:
裴属定理
在数论中,裴蜀定理是一个关于最大公约数(或最大公约式)的定理,裴蜀定理得名于法国数学家艾蒂安·裴蜀。
裴蜀定理(或贝祖定理)得名于法国数学家艾蒂安·裴蜀,说明了对任何整数a、b和它们的最大公约数d,关于未知数x和y的线性不定方程(称为裴蜀等式):若a,b是整数,且gcd(a,b)=d,那么对于任意的整数x,y,ax+by都一定是d的倍数,特别地,一定存在整数x,y,使ax+by=d成立。
换句话说,裴蜀定理表明,如果a和b的最大公约数为d,则存在整数x和y,使得ax + by = d,同时对于任意整数k,ax + by = kd的解也存在。这个定理的一个重要应用是判断两个整数是否互质,即它们的最大公约数是否为1。
证明及详情见:
裴蜀定理_百度百科 (baidu.com)https://baike.baidu.com/item/%E8%A3%B4%E8%9C%80%E5%AE%9A%E7%90%86/0
公倍数
简介
公倍数(common multiple)是指在两个或两个以上的自然数中,如果它们有相同的倍数,这些倍数就是它们的公倍数。公倍数中最小的,就称为这些整数的最小公倍数(lowest common multiple) [1]。
举例
A和B A/B=C 如果A能被B整除,则A为B和C的公倍数 两个数A和B,它们的公倍数就是既是A的倍数又是B的倍数的数,即能同时被A、B整除的数 比如说:12和15,它们的公倍数是60,120,180,等等 在这些公倍数中最小的那一个就叫最小公倍数,就是60。
详情见
公倍数_百度百科 (baidu.com)https://baike.baidu.com/item/%E5%85%AC%E5%80%8D%E6%95%B0/1064191
三、最大公因数的实现
穷举法
当我们想到求解m,n的最大公因数时,脑海中第一个浮现的念头就是利用for循环条件m与n同时除以 同一个数 i ,然后让i++,直到求出等于两数其一为止。因为这种方法几乎将所有的元素都取了一遍因此叫做穷举法。即,for(i=1;i<n;i++);
#include <stdio.h>
int main()
{
int m=0,n=0;
int i=1,ret=0;
scanf("%d%d",&m,&n);
//除数不能为0,因此循环从i=1开始。
for(i=1;i<=m;i++)
{ //当m<n时,因为最大公因数一定小于等于m,所以i<=m条件成立;
//当m>n时,且当i>n时,n%i一定不成立,因数不会赋值给ret
//因此,m与n相对大小,对程序的相对运行没有影响。
if((m%i==0)&&(n%i==0))
ret=i; //将因数赋值给ret
}
printf("%d",ret);
return 0;
}
辗转相除法
由上述提到的裴属定理可知,辗转相除法最大的用途就是用来求两个数的最大公约数。
辗转相除法又叫做欧几里得法,两个整数的最大公约数等于其中较小的数和两数的差的最大公约数。
详情见:
辗转相除法介绍 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/324578532
#include<stdio.h>
int main()
{
int m,n,r;
scanf("%d%d",&m,&n);
while(r=m%n)
{
m=n;
n=r;
}
printf("最大公因数为:%d\n",n);
return 0;
}
更相减损术
更相减损之术,又叫尼考曼彻斯法,其思想最早见于西汉《九章算术》中,“可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之”。
它的白话译文是:如果需要对分数进行约分,那么)可以折半的话,就折半(也就是用2来约分)。如果不可以折半的话,那么就比较分母和分子的大小,用大数减去小数,互相减来减去,一直到减数与差相等为止,用这个相等的数字来约分。
详情见:
#include <stdio.h>
int main()
{
int m=0,n=0;
scanf("%d%d",&m,&n);
while(m!=n) //循环相减直到m=n
{
if(m>n) //保证较大数减去较小数,结果不是负数。
m-=n;
else
n-=m;
}
printf("%d",m);//结果m=n,因此不必担心m,n位置互换
return 0;
}
四、最小公倍数的实现
穷举法
常言道,万事不决,量子力学。而对于公倍数而言,我们可以万事不决,利用穷举法,利用循环全部寻找出来。
#include <stdio.h>
int main()
{
int n,m,i,ret;
scanf("%d%d",&m,&n);
for(i=m;i<=m*n;i++)//最小公倍数的最坏情况是两数互为质数,因此循环到m*n结束。
{
if(i%m==0&&i%n==0)
{
ret=i;
break; //找到最小公倍数后跳出循环;
}
}
printf("最小公倍数是:%d\n",ret);
return 0;
}
辗转相除法
我们知道:当利用短除法求出m,n最大公因数之后,两数互质,因而将两数相乘再乘以最大公因数就是最小公倍数。
【动画笔记】辗转相除法——求最大公约数和最小公倍数 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/508687942
#include<stdio.h>
int main()
{
int m,n,r;
int com=0;
scanf("%d%d",&m,&n);
int i=m,j=n;//保留m,n的数值
while(r=m%n)
{
m=n;
n=r; //求出最大公因数n
}
com=i*j/n;
printf("最小公倍数为:%d\n",com);
return 0;
}
这种方法的好处是他几乎能将所有能求出最大公因数的方法为雏形,演化成为最小公倍数的解法,几乎是“代码界的缝合怪”。
叠乘法
已知两个数的公倍数一定与这两个数存在倍数关系,那么求解最小公倍数我们就可以将其中一个数依次扩大1倍、2倍、3倍……直到出现第一个扩大n倍的数可以同时整除这两个数,这个数就是最小公倍数。
#include<stdio.h>
int main()
{
int m,n;
int i=1;
int com=0;
scanf("%d%d",&m,&n);
while(m*i%n!=0)
{
i++;
}
com=m*i;
printf("最小公倍数为:%d\n",com);
return 0;
}