欧几里德算法~~

原文:http://blog.csdn.net/leader_one/article/details/75222771

觉得大佬写的不错,防止忘记,备份一篇

说在前面

出于尊重,简单介绍一下欧几里得(想了解更多自己百度去) 
欧几里得(希腊文:Ευκλειδης ,公元前330年—公元前275年),古希腊数学家。他活跃于托勒密一世(公元前364年-公元前283年)时期的亚历山大里亚,被称为“几何之父”,他最著名的著作《几何原本》是欧洲数学的基础,提出五大公设,欧几里得几何,被广泛的认为是历史上最成功的教科书。欧几里得也写了一些关于透视、圆锥曲线、球面几何学及数论的作品。


欧几里得算法

简介欧几里得算法 
欧几里得算法(也称辗转相除法)是目前已知求最大公约数的最快通用算法,具有代码复杂度低、易理解、用途广等诸多优点,也是OI中不可或缺的的一种算法。(信息学白皮书里也有提到) 
若有两个数a和b,需要求a和b的最大公约数,怎么办? 
枚举它们的因子? 小数据可以,大数据的话,这个O(n)的算法就图森破了。 
分解质因数?在大数面前也是拿衣服的。 
总不能不搞吧,上帝喊了一声“效率”,于是我们便有了O(log n)效率极高的欧几里得算法。


引理 
欧几里得有个非常强的定理,即gcd(a,b)=gcd(b,a mod b),让我们来证明一下(mod 是取余,gcd是最大公约数,| 是能整除) 
假设a、b的公约数为k,a = bx + y 
则 k | a,k | b,a mod b=y 
因为 k | b,所以 k |bx,又因为 k | a,所以 k | (a - bx),即 k | y 
而a mod b = y,所以 k | a mod b 
再假设b、a mod b的公约数为kk,同理得 kk | a,所以(a,b)和(b,a mod b)的公约数是相同的,所以它们的最大公约数也是相同的 
所以gcd(a,b)=gcd(b,a mod b)


时间复杂度(讨论情况为a>=b) 
a mod b必然是小于a/2的,而上一次的b会变成下一次的a,上一次的a mod b会变成下一次的b,最坏情况也就是b在a/2附近,即a mod b在a/2附近。在最坏情况时每次的值也会减少一半,所以说时间复杂度是O(log n)的。(实际中往往会更低)


算法实现 
有了以上的引理算法实现就非常简单了,递归和非递归形式都可以。任何数与0的最大公约数是它本身,所以一直操作直到b = 0时的a就是原a,b的最大公约数了。 
伪代码:

while(b!=0)
{
    r = a % b;
    a = b;
    b = r;
}
//最终的a即为原a,b最大公约数
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

扩展欧几里得算法

简介扩展欧几里得算法 
扩展欧几里得算法的功能就更强大了,它可以用来求二元一次方程的通解,还可以用来求乘法逆元。 
在此顺便简介一下乘法逆元: 
若有 a*x ≡ 1 (mod m),则称 x 为a关于m的乘法逆元,等价式 a * x+m * y = 1 
这就也是个二元一次方程了,ExGcd可搞。


引理 
裴蜀定理:若ax+by = z,则 gcd(a,b)| z 
再顺手证明一下裴蜀定理: 
设k = gcd(a,b),则 k | a, k | b,根据整除的性质,有 k | (ax+by) 
设 s为ax+by的最小正数值 
再设 q = [a / s](a整除s的值);r = a mod s = a-q(ax+by) = a(1 - qx)+b(-qy); 
由此可见r也为a,b的线性组合;(ax+by称为a,b的线性组合) 
又因为s为a,b的线性组合的最小正数值,0<= r < s,所以r的值为0,即 a mod s = r =0;s | a; 
同理可得 s | b,则 s | k; 
又因为 k | (ax+by),s为ax+by的最小正数值,所以 k | s; 
因为 s | k,k | s,所以s = k; 
原命题得证。 
点这里有裴蜀定理与乘法逆元的详解


如何求解 (以下讨论a>b) 
显然当 b=0,gcd(a,b)=a。此时 x=1,y=0; 
当a>b>0 时 
设 ax1+ by1= gcd(a,b); 
bx2+ (a mod b)y2= gcd(b,a mod b); 
根据欧几里德原理有 gcd(a,b) = gcd(b,a mod b); 
则:ax1+ by1= bx2+ (a mod b)y2; 
即:ax1+ by1= bx2+ (a - [a / b] * b)y2 = ay2+ bx2- [a / b] * by2;(a mod b = a - [a / b]*b;[a / b]代表a整除b) 
也就是ax1+ by1 = ay2 + b(x2- [a / b] *y2); 
根据恒等定理得:x1=y2;y1=x2- [a / b] *y2; 
这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2 
由引理我们知道:ax+by = z,z为gcd(a,b)若干倍,所以我们先求解ax+by = gcd(a,b),再将求出的解乘以 z/gcd(a,b)就好了。


算法实现 
我们依旧递归实现,因为上一次的x,y与下一次的x,y的值有关,所以我们从x=1,y=0(此时b=0)的情况开始递归上来,套公式就好了。(a,b下去,x,y上来) 
伪代码:

int exGcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x = 1;
        y = 0;
        return a;
    }
    int r = exGcd(b,a%b,x,y);
    t = x; x = y;
    y = t-a/b*y;
    return r;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

按照惯例再说两句

本人蒟蒻一枚,博客难免有误,发现错误的大牛牪犇可以发私信联系本人指正错误。另外本博客可能会更新,可以考虑收藏一下。 
好了,暂时就讲这么多了,如果绝对这里讲解得不够详细,也可以私信联系本人交流一下。 
欢迎转载,转载请说明出处,谢谢。

猜你喜欢

转载自blog.csdn.net/gao506440410/article/details/81181573