#include<stdio.h>
int main()
{
int m,n,r;
printf("请输入两个大于1的正整数:");
scanf("%d %d",&m,&n);
while(n!=0)
{
r=m%n;
m=n;
n=r;
}
printf("它们的最大公约数为:%d",m);
}
最一开始看到以上算法的小白是不是感觉很懵?凭什么模余后的n赋值给m?余数赋值给n?凭什么?那么我从“除法的本质是减法”(我想大家应该都知道,不过也有同志是不知道的,这里我给出简短的理解性说明,比如15➗5=3余0,它实际上做的操作是15-5=10;10-5=5;5-5=0;一共做了三步,用5把15用3步给分完了,没有余数,所以这里的3(步)就是商,这里的0就是余数)来给出我的理解。
先考察17 和 7,这两个素数(因为它们的最大公约数为1,整个过程展现的比较完整,这种推导会,其他的只是它们的中间过程)
先考虑“辗转相减法”给出的步骤:
辗转相减法它的本质是将“单位份数”不断逼近最大公约数,而余数就是让它不断逼近,重新作为单位份数的划分根据。
再核心一点,我关心的到底是什么?是余数!我希望余数为0,到这一步之前的除数n就是最大公约数(最大单位份数)这正是“公约”的“元”。
所以在这里有一个对应关系,关于每一步,如果余数为0那么,除数n(单位份数)就是这一步我们认为的最大公约数,如果有余数,那么余数才是更接近最大公约数的数,我们采用的是逼近的思想。
question:17可以分成几个完整的7?--2个,17被这两个7填满之后还多3,而这个3,应当在7里继续分,为什么?因为我的目标就是要把余数清零,把这两个数用寻找过程中的最大公约数分配完。
7可以分成几个完整的3?--2个,多1...
3可以分成几个完整的1?--3个,还多0,完成,最大公约数就是1
通过以上可以看到,那些“17可以分成几个完整的7?--2个的‘个数’”,实际上是进行减法的步骤数,我们关心的余数其实可以用m%n就可以实现,而这里的余数一定小于这一步的单位份数(比如这一步的单位份数就是7),那么很显然这个单位份数还不够逼近,还有余数,那么余数才是更逼近单位份数的数,所以我将它作为下一步的除数。
类似的,比如15和5,我先定义小的数作为单位份数,15对5做3次减法运算,正好可以把它分完,那么这个单位份数5就是他们的最大公约数。
现在得到了这个原理和结果,我们再回到17 和 7的这个问题,我们在考虑的时候发现明显比15 和 5步骤要多多了,原因在于这两个数是素数,约数只有1和它本身,我们在代码优化的时候可以在之前先加上判断素数的代码,两个都是素数,别烦了,最大公约数就是1.
下面给出代码:
#include<stdio.h>
#include<math.h>
int ifprime(int mn)
{
int i=(int)sqrt(mn);
int a=2;
for(;a<=i;a++)//循环只需要判断输入数据的平方根的位置即可
{
if(i%a==0)
return 0;
}
if(a>i) return 1;
}
int main()
{
int m,n,r;
printf("请输入两个大于1的正整数:");
scanf("%d %d",&m,&n);
//先判断这俩数是不是都是素数,是,则直接输出1
if(ifprime(n)&&ifprime(m))printf("它们的最大公约数为:1");
while(n!=0)
{
r=m%n;
m=n;
n=r;
}
printf("它们的最大公约数为:%d",m);
}
关于以上代码判断素数为什么到一个数的平方根就可以,在这里不再赘述,这是最简方法,有机会我会在我的其他文章中对它进行解释。
如果有问题欢迎随时与我沟通。