最大公约数

  一、最大公约数

  1、定义:最大公因数,也称最大公约数、最大公因子,指两个或多个整数共有约数中最大的一个。a,b的最大公约数记为(a,b),同样的,a,b,c的最大公约数记为(a,b,c),多个整数的最大公约数也有同样的记号。

     例如:12、16的公约数有1、2、4,其中4就是12、16的最大公约数。

二、求解方法

1、朴素算法:从m、n较小的一个数开始枚举,如果都能被m、n整除,那么该数就是两数的最大公约数,否则继续减一,直至枚举到1为止。(这个算法复杂度十分不优秀,只是帮助大家理解如何求最大公约数,彰显辗转相除算法的优秀)。

                       例如:求12、8的最大公约数

                          解:先枚举8  12/8=1......4     8/8=1......0

                                           7   12/7=1......5     8/7=1......1

                                           6   12/6=2......0     8/6=1......2

                                           5   12/5=2......2     8/5=1......3

                                           4   12/4=3......0     8/4=2......0

                            因此最大公约数为4。

例1  求两个正整数m,n的最大公约数。
     【方法1】:求任意两个自然数m和n的最大公约数,可以想到其最大的可能就是两个数中的较小者min,最小可能是1。所以,可以设最大公约数gcd从min开始进行判断,若gcd>1并且没有同时整除m和n,那么就gcd-1,重复判断是否整除。
  【参考程序】
  #include<iostream>
  using namespace std;
  int main()
  {
      int m,n,gcd;
      cin>>m>>n;
      gcd=m>n?n:m;                     //注意此处的特殊写法
      while (gcd>1&&(m%gcd!=0||n%gcd!=0))
         gcd--;                                 //每次减1寻找最大公约数
      cout<<gcd<<endl;               //输出最大公约数
      return 0;
}
2、更相减损术

(1)《九章算术》是中国古代的数学专著,其中的“更相减损术”可以用来求两个数的最大公约数,原文是:可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。

白话文译文:
(如果需要对分数进行约分,那么)可以折半的话,就折半(也就是用2来约分)。如果不可以折半的话,那么就比较分母和分子的大小,用大数减去小数,互相减来减去,一直到减数与差相等为止,用这个相等的数字来约分。
(2)
  第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
  第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
  则第一步中约掉的若干个2的积与第二步中等数的乘积就是所求的最大公约数。
  其中所说的“等数”,就是公约数。求“等数”的办法是“更相减损”法。
(3)
  例2  用更相减损术求98与63的最大公约数。
  解:由于63不是偶数,把98和63以大数减小数,并辗转相减:
  98-63=35
  63-35=28
  35-28=7
  28-7=21
  21-7=14
  14-7=7
  所以,98和63的最大公约数等于7。
  例3  用更相减损术求260和104的最大公约数。
  解:由于260和104均为偶数,首先用2约简得到130和52,再用2约简得到65和26。
  此时65是奇数而26不是奇数,故把65和26辗转相减:
  65-26=39
  39-26=13
  26-13=13
  所以,260与104的最大公约数等于13乘以第一步中约掉的两个2,即13*2*2=52。
3.辗转相除(gcd(a,b))
  (1)用除数和余数反复做除法运算,当余数为 0 时,取当前算式除数为最大公约数。
  (2)步骤:
                     1)求a除以b的余数r;    
                     2)当r!=0,执行第3)步;若r==0,则n为最大公约数,算法结束。    
                     3)将b的值赋给a,将r的值赋给b;再求a除以b的余数r。    
                     4)转到第2)步
4.二进制最大公约数算法
    1)递归终止条件:gcd(m,m)=m。
    2)递归关系式:     m<n时:gcd(m,n)=gcd(n,m)    
                                 m为偶数,n为偶数:gcd(m,n)=2*gcd(m/2,n/2)    
                                 m为偶数,n为奇数:gcd(m,n)=gcd(m/2,n)    
                                 m为奇数,n为偶数:gcd(m,n)=gcd(m,n/2)    
                                 m为奇数,n为奇数:gcd(m,n)=gcd(n,m-n)    
    该方法和方法1相比更适合求高精度数的最大公约数,因为只涉及除2和减法操作,而辗转相除法则需要用到高精度除法。
例1  求两个正整数m,n的最大公约数。
【方法2】:求两个整数的最大公约数可以采用辗转相除法即欧几里德算法。对于任意两个自然数m和n,用m,n,r分别表示被除数、除数、余数,那么m和n的最大公约数等于n和r的最大公约数。以下是辗转相除法的算法:     1)求m除以n的余数r;    
                     2)当r!=0,执行第3)步;若r==0,则n为最大公约数,算法结束。    
                     3)将n的值赋给m,将r的值赋给n;再求m除以n的余数r。    
                     4)转到第2)步
  【参考程序】
    #include <iostream>
    using namespace std;
    int main () { 
      int m,n;   
      cin>>m>>n;   
      int r =m % n;   
      while (r!=0)             //也可以使用 while (r),c++中 非0即真   
      {   
           m=n;  
           n=r;     
           r=m % n;     }   
       cout<<"最大公约数="<<n<<endl;   
       return 0;
    }
例4  用递归方法求两个数m和n的最大公约数。(m>0,n>0)
   【方法1】求两个数的最大公约数,可以用枚举因子的方法,从两者中较小的数枚举到能被两个数同时整除且是最大的约数的方法;也可以用辗转相除法,这里采用递归实现辗转相除算法:
       ①求m除以n的余数;
       ②如果余数不为0,则让m=n,n=余数,重复步骤①,即调用子程序;
       ③如果余数为0,则终止调用子程序;
       ④输出此时的n值。
     #include<iostream>
  using namespace std;
  int gcd(int,int);
  int main()
  {   int m,n;
      cin>>m>>n;
      cout<<" gcd="<<gcd(m,n)<<endl;
      return 0;
  }
  int gcd(int m,int n)
  {
       return m%n==0?n:gcd(n,m%n);
  }
  【方法2】二进制最大公约数算法:
    (1)递归终止条件:gcd(m,m)=m。
    (2)递归关系式:     m<n时:gcd(m,n)=gcd(n,m)    
                                 m为偶数,n为偶数:gcd(m,n)=2*gcd(m/2,n/2)    
                                 m为偶数,n为奇数:gcd(m,n)=gcd(m/2,n)    
                                 m为奇数,n为偶数:gcd(m,n)=gcd(m,n/2)    
                                 m为奇数,n为奇数:gcd(m,n)=gcd(n,m-n)    
    该方法和方法1相比更适合求高精度数的最大公约数,因为只涉及除2和减法操作,而辗转相除法则需要用到高精度除法。
程序如下:
  #include<iostream>
  using namespace std;
  int gcd(int m,int n) { 
        if(m==n)return m;                     //递归终止条件     
        if(m<n)return gcd(n,m);   
        if(m%2==0)     {        
            if(n%2==0)    return 2*gcd(m/2,n/2); //m为偶数,n为偶数       
            else return gcd(m/2,n);          //m为偶数,n为奇数  
          }   
      else     { 
         if(n%2==0)  return gcd(m,n/2);     //m为奇数,n为偶数         
         else return gcd(n,m-n);          //m为奇数,n为奇数   
       }
     }
  int main() {
         int m,n;
         cin>>m>>n;
         cout<<gcd(m,n)<<endl;  
         return 0;
    }
说明:以上内容参考百度、信息学奥赛一本通,仅限于自己内部使用,帮助理解最大公约数。

 

 

posted @   ddfy198811  阅读(2930)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示