欧几里得算法与同余方程

欧几里得算法

  说起数学家不得不提起欧几里得,而欧几里得的欧几里得算法(gcd)直到现在仍在计算机与数学领域有着卓越的贡献

  欧几里得算法非常简单,简而言之就是gcd(a,b)=gcd(b,a%b)。如果你是小升初时学奥数的受害者,那你一定会很眼熟:这不是辗转相除法吗!!    是的其实你早就接触过这个算法了,而求出最小公约数只是这个算法的最最基本的用法(当然也用的最多),但在算法这个版块里,它的用法基本就不同了。

证明方法(以下摘自百度百科)

 其计算原理依赖于下面的定理:
定理:两个整数的最大公约数等于其中较小的那个数和两数相除余数的最大公约数。最大公约数(Greatest Common Divisor)缩写为GCD。
gcd(a,b) = gcd(b,a mod b) (不妨设a>b 且r=a mod b ,r不为0)
 

证法一

a可以表示成a = kb + r(a,b,k,r皆为正整数,且r<b),则r = a mod b
假设d是a,b的一个公约数,记作d|a,d|b,即a和b都可以被d整除。
而r = a - kb,两边同时除以d,r/d=a/d-kb/d=m,由等式右边可知m为整数,因此d|r
因此d也是b,a mod b的公约数
假设d是b,a mod b的公约数, 则d|b,d|(a-k*b),k是一个整数。
进而d|a.因此d也是a,b的公约数
因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证。

证法二

第一步:令c=gcd(a,b),则设a=mc,b=nc
第二步:可知r =a-kb=mc-knc=(m-kn)c
第三步:根据第二步结果可知c也是r的因数
第四步:可以断定m-kn与n互素【否则,可设m-kn=xd,n=yd,(d>1),则m=kn+xd=kyd+xd=(ky+x)d,则a=mc=(ky+x)dc,b=nc=ycd,故a与b最大公约数≥cd,而非c,与前面结论矛盾】
从而可知gcd(b,r)=c,继而gcd(a,b)=gcd(b,r),得证
注意:两种方法是有区别的。

 

 


 

裴蜀定理

  欧几里得算法不仅仅用于求最大公约数,还可以用于求出形如ax+by=c,a mod b = c(这二者本质上是相差不大的)的解。当然只凭借欧几里得算法是不够的,这里补充一个数学定理,裴蜀定理

  (以下摘自百度百科)

  裴蜀定理说明了对任何整数a、b和它们的最大公约数d ,关于未知数 x 和 y 的线性丢番图方程(称为裴蜀等式)。

  关于未知数x和y的线性不定方程(称为裴蜀等式):若a,b是整数,且gcd(a,b)=d,那么对于任意的整数x,y,ax+by都一定是d的倍数,特别地,一定存在整数x,y,使ax+by=d成立。
  它的一个重要推论是:a,b互质的充要条件是存在整数x,y使ax+by=1
 
证明方法(以下摘自百度百科)

  (1)若b=0,则(a,b)=a.这时定理显然成立。

  (2)若a,b不等于0.

  ∵(a,b)=(a,-b)∴不妨设a,b都大于零,a>=b,(a,b)=d

  对ax+by=d,两边同时除以d,可得(a1)x+(b1)y=1,其中(a1,b1)=1。

  转证(a1)x+(b1)y=1。由带余除法:

  a1=(q1)b+(r1),其中0=<r1<b1

  b1=(q2)(r1)+(r2),其中0=<r2<r1

  (r1)=(q3)(r2)+(r3),其中0=<r3<r2

  .....

  (rn-3)=(qn-1)(rn-2)+(rn-1)

  (rn-2)=(qn)(rn-1)+(rn)

  (rn-1)=(qn+1)(rn)

  于是,有(a1,b1)=(b1,r1)=(r1,r2)=...=(rn-1,rn)=1

  故

  (rn-2)=(xn)(rn-1)+1

  即1=(rn-2)-(xn)(rn-1)

  由倒数第三个式子(rn-1)=(rn-3)-(xn-1)(rn-2)代入上式,得

  1=[1+(xn)(xn-1)](rn-2)-(xn)(rn-3)

  然后用同样的办法用它上面的等式逐个地消去(rn-2),...(r1),

  可证得1=(a1)x+(b1)y。

(这两个定理证明看不懂或不看都无所谓,会用就行)


拓展欧几里得算法
  有了两个前置算法之后,就可以明白如何使用扩展欧几里得(exgcd)算法解同余方程了
  例(洛谷p1082,2012提高组d2t1)同余方程
  

  题目描述

    求关于x的同余方程ax1(modb) 的最小正整数解。

  输入格式

    一行,包含两个正整数 a,b,用一个空格隔开。

  输出格式

    一个正整数x0,即最小正整数解。输入数据保证一定有解。


 

  这道题不难,但是扩欧的很经典的用法,这里略过暴力直接讨论正解,

  很显然这道题可以转化为ax+by=1的最小正整数解,那么就可以从这个角度入手。首先看到欧几里得算法,gcd(a,b)=gcd(b,a%b),又由裴蜀定理可得ax1+by1=gcd(a,b)=gcd(b,a%b)=bx2+(a%b)y2。a%b可以换一种等价的表达方式即a-a/b*b(a/b取整)  ,然后方程就可以变形为ax1+by1=ay2 +b(x​2−(a/b)y2 )从而推出x1=y2,y1=x2(a/b)y2。所以由一组解可以推出无数组解。而有一组解必然为x=1,y=0(其实当欧几里得算法运行至b=0时,与y没得关系)。然后最后对x进行一下处理使其成为方程的最小正整数解。

  代码如下

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 long long int x,y;
 5 int exgcd(int a,int b)
 6 {
 7     if(b==0)
 8     {
 9     x=1;
10     y=0;
11     return 0;
12     }
13     exgcd(b,a%b);
14     long long int t;
15     t=x;
16     x=y;
17     y=t-(a/b)*y;
18     return 0;
19 }
20 int main()
21 {
22     int a,b;
23     cin>>a>>b;
24     exgcd(a,b);
25     while(x<b)
26         x+=b;
27     cout<<(x+b)%b;
28 }

  总结

  扩欧不难,且很有用(而且还要考)


    
 
posted @ 2019-07-25 10:30  Malthael  阅读(756)  评论(0)    收藏  举报