算法15---数论5---最大公约数,最小公倍数

本文详细介绍了最大公约数(GCD)和最小公倍数(LCM)的计算方法,包括辗转相除法、stein算法及欧几里得算法,并提供了相应的源代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法16---数论5---最大公约数,最小公倍数

有一个难点就是stein算法的证明;
 
 
 
首先引进一个符号:g_c_d是greatest common divisor(最大公约数)的缩写,g_c_d( x,y ) 表示x和y的最大公约数。然后有一个事实需要了解:一个奇数的所有约数都是奇数。这个很容易,下面我们要用到。
  来研究一下最大公约数的性质,我们发现有 g_c_d( k*x,k*y ) = k*g_c_d( x,y ) 这么一个非常好的性质(证明我就省去了)。说他好是因为他非常符合我们化小的思想。我们试取 k=2 ,则有 g_c_d( 2x,2y ) = 2 * g_c_d( x,y )。这使我们很快联想到将两个偶数化小的方法。那么一奇一个偶以及两个奇数的情况我们如何化小呢?
 
  先来看看一奇一偶的情况: 设有2x和y两个数,其中y为奇数。因为y的所有约数都是奇数,所以 a = g_c_d( 2x,y ) 是奇数。根据2x是个偶数不难联想到,a应该是x的约数。我们来证明一下:(2x)%a=0,设2x=n*a,因为a是奇数,2x是偶数,则必有n是偶数。又因为 x=(n/2)*a,所以 x%a=0,即a是x的约数。因为a也是y的约数,所以a是x和y的公约数,有 g_c_d( 2x,y ) <= g_c_d( x,y )。因为g_c_d( x,y )明显是2x和y的公约数,又有g_c_d( x,y ) <= g_c_d( 2x,y ),所以 g_c_d( 2x,y ) = g_c_d( x,y )。至此,我们得出了一奇一偶时化小的方法。
 
 再来看看两个奇数的情况:设有两个奇数x和y,似乎x和y直接向小转化没有什么太好的办法,我们可以绕个道,把x和y向偶数靠拢去化小。不妨设x>y,我们注意到x+y和x-y是两个偶数,则有 g_c_d( x+y,x-y ) = 2 * g_c_d( (x+y)/2,(x-y)/2 ),那么 g_c_d( x,y ) 与 g_c_d( x+y,x-y ) 以及 g_c_d( (x+y)/2,(x-y)/2 ) 之间是不是有某种联系呢?为了方便我设 m=(x+y)/2 ,n=(x-y)/2 ,容易发现 m+n=x ,m-n=y 。设 a = g_c_d( m,n ),则 m%a=0,n%a=0 ,所以 (m+n)%a=0,(m-n)%a=0 ,即 x%a=0 ,y%a=0 ,所以a是x和y的公约数,有 g_c_d( m,n )<= g_c_d(x,y)。再设 b = g_c_d( x,y )肯定为奇数,则 x%b=0,y%b=0 ,所以 (x+y)%b=0 ,(x-y)%b=0 ,又因为x+y和x-y都是偶数,跟前面一奇一偶时证明a是x的约数的方法相同,有 ((x+y)/2)%b=0,((x-y)/2)%b=0 ,即 m%b=0 ,n%b=0 ,所以b是m和n的公约数,有 g_c_d( x,y ) <= g_c_d( m,n )。所以 g_c_d( x,y ) = g_c_d( m,n ) = g_c_d( (x+y)/2,(x-y)/2 )。
 
我们来整理一下,对两个正整数 x>y :
1.均为偶数 g_c_d( x,y ) =2g_c_d( x/2,y/2 );
2.均为奇数 g_c_d( x,y ) = g_c_d( (x+y)/2,(x-y)/2 );
2.x奇y偶 g_c_d( x,y ) = g_c_d( x,y/2 );
3.x偶y奇 g_c_d( x,y ) = g_c_d( x/2,y ) 或 g_c_d( x,y )=g_c_d( y,x/2 );
 
补充说明;
最大公约数还有一种方法,就是用欧几里得算法求最大公约数;
举例说明:
求gcd(30,21)
采用欧几里得算法:
伪代码:
euclid(a,b)
if b==0
     return a;
else return euclid(b,a mod b);
 
example:
euclid(30,21)=euclid(21,9)=euclid(9,3)=euclid(3,0)=3
 
 
  1 /*
  2     题目:最大公约数
  3     author taoliu——alex  2016.10   number4
  4 
  5     主要实现:
  6     求最大公约数
  7 
  8     我们主要采用两种方法来实现,一种是最常用的辗转相除法;
  9     另一种采用stein 算法
 10     第一种适合比较小的数字之间的计算;当时如果数据过大,就不适合了;
 11     stein算法就采用的是整数的以为和普通的加减方法实现的。
 12 
 13 
 14     再补充一种使用欧几里得算法求最大公约数的方法
 15 
 16 */
 17 
 18 
 19 
 20 
 21 
 22 #include <stdio.h>
 23 
 24 
 25 
 26 /*
 27 辗转相除法;
 28 */
 29 int gcd(int a,int b)
 30 {
 31     int m;
 32     int n;
 33     if (a>b)
 34     {
 35         m=a;
 36         n=b;
 37     }
 38     else
 39     {
 40         m=b;
 41         n=a;
 42     }
 43     int r=m%n;
 44     while(r!=0)
 45     {
 46         m=n;
 47         n=r;
 48         r=m%n;
 49     }
 50     return n;
 51 }
 52 
 53 
 54 /*
 55 方法2:stein算法;
 56 假设计算a和b两个数的最大公约数;
 57 (1)首先判断a或者b的值,如果a=0,b就是最大公约数,相反,a就是最大公约数;如果a和b都不为0;就执行下一步;
 58 (2)完成a1=a,b1=b,c1=1的赋值;
 59 (3)判断an,bn是否为偶数,若都为偶数,则使a(n+1)=an/2,b(n+1)=bn/2,c(n+1)=cn*2;如果判断an和bn中包含一个技术,则执行(4)(5)(6);
 60 (4)若an是偶数,bn是奇数,则完成a(n+1)=an/2,b(n+1)=bn,c(n+1)=cn的赋值;
 61 (5)若an是奇数,bn是偶数,则完成a(n+1)=an,b(n+1)=bn/2,c(n+1)=cn的赋值;
 62 (6)若an,bn是奇数,,则完成a(n+1)=|an-bn|,b(n+1)=min(an,bn),c(n+1)=cn的赋值;
 63 (7)n累加1,跳转到第(3)步进行下一轮运算。
 64 
 65 */
 66 
 67 int gcd2(int a,int b)
 68 {
 69     int m,n;
 70     if (a>b) //还是使用m保存较大的数;
 71     {
 72         m=a;
 73         n=b;
 74     }
 75     else
 76     {
 77         m=b;
 78         n=a;
 79     }
 80 
 81     if (n==0)
 82     {
 83         return m;
 84     }
 85     if (m%2==0&&n%2==0)
 86     {
 87         return gcd2(m/2,n/2);
 88     }
 89     if (m%2==0)
 90     {
 91         return gcd2(m/2,n);
 92     }
 93     if (n%2==0)
 94     {
 95         return gcd2(m,n/2);
 96     }
 97     return gcd((m+n)/2,(m-n)/2);
 98 }
 99 
100 
101 //欧几里得算法
102 int euclid(int a,int b)
103 {
104     int m,n;
105     if (a>b) //还是使用m保存较大的数;
106     {
107         m=a;
108         n=b;
109     }
110     else
111     {
112         m=b;
113         n=a;
114     }
115     if (n==0)
116     {
117         return m;
118     }
119     else
120         return euclid(b,a%b);
121 }
122 
123 
124 int main()
125 {
126     int ans1=gcd(6,4);
127     printf("%d\n",ans1 );
128     int ans2=gcd2(9,3);
129     printf("%d\n",ans2 );
130     int ans3=gcd2(12,9);
131     printf("%d\n",ans3 );
132     return 0;
133 }

 

最小公倍数源代码
 
 
 1 /*
 2     题目:最小公倍数
 3     author taoliu——alex  2016.10   number4
 4 
 5     主要实现:
 6     求最小公倍数
 7 
 8 
 9 */
10 #include <stdio.h>
11 
12 
13 
14 int gcd(int a,int b)
15 {
16     int m;
17     int n;
18     if (a>b)
19     {
20         m=a;
21         n=b;
22     }
23     else
24     {
25         m=b;
26         n=a;
27     }
28     int r=m%n;
29     while(r!=0)
30     {
31         m=n;
32         n=r;
33         r=m%n;
34     }
35     return n;
36 }
37 
38 
39 int lcm(int a,int b)
40 {
41     int c=gcd(a,b);
42     int d=(a*b)/c;
43     return d;
44 
45 }
46 
47 
48 
49 int main()
50 {
51     int ans=lcm(3,4);
52     printf("%d\n", ans);
53     return 0;
54 }

 

 
 
 
 

转载于:https://www.cnblogs.com/tao-alex/p/5941079.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值