• 扩展欧几里德算法(gcd扩展使用)


    这一段是2018暑假写的

    发现自己一学期没有写数论,啥都不会了!!!惊讶!!!!!

    gcd(a,b)=gcd(a,b%a)

    注意:写代码时候递归的时候一定要确保a<b,否则代码不好写,还会出现奇怪的bug,停止条件是a==0.

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    int gcd(int a,int b)
    {
    	if(a>b) swap(a,b);
    	if(a==0) return b;
    	else
    	{
    		gcd(a,b%a);
    	}
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	printf("%d",gcd(n,m));
    	return 0;
    }
    

    下面这一段是很久以前写的了!

    首先让我们先来普及一下,关于gcd的知识,这里几个字就可以搞定,gcd(a,b)就是指a,b的最大公约数,我靠,你可能会说这个有什么用呢?

    不要着急,我们马上就会进行讲解:

    首先先来普及一些基本概念:

    首先他们必须满足贝祖等式(好高大上的名字啊!): ax+by = gcd(a, b)。

    于是由这个定理,我们成功推出了:(说实话我TM也没有听懂是怎么推的,呵呵!)

    所以,我们由gcd函数的知识,可以成功的推出,如下两个递归时的方程:

    ax+by=gcd(a,b);
    因为a=a%b+(a/b)*b;
    带入化简后:b((a/b)*x+y)+(a%b)*x=gcd(b,a%b);
    

    下面为证明过程:

       设:a>b。
      推理1,显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
        	//-------------------------------------------------------------
      推理2,ab!=0 时
      设 ax+by=gcd(a,b);//important
      bx1+(a%b)y1=gcd(b,a%b);
      根据正常欧几里德原理有 gcd(a,b)=gcd(b,a%b);
      则:ax+by=bx1+(a%b)y1;
      	因为a=a%b+(a/b)*b;代入
      即:ax+by=bx1+(a-(a/b)*b)y1=ay1+bx1-(a/b)*by1=ay1+b(x1-(a/b)*y1);
      由此得:x=y1 ,y=x1-(a/b)*y1;
      	//-------------------------------------------------------------
      这样我们就得到了求解 x,y 的方法:x,y 的值基于 x1,y1.
       上面的思想是以递归定义的,因为 gcd 不断的递归求解一定会有个时候 b=0,所以递归可以结束。
    

    这个推理应该非常的完美了吧!

    我认为这份推理很不错的诠释了我给lry讲了半天的东西是怎么来的(因为他设了两个变量),所以讲的非常清楚,点赞!

    那么相信大家gcd应该是没有什么问题了:

    下面是代码实现:

    #include<bits/stdc++.h>
    using namespace std;
    int a,b,x,y,s;
    void exgcd(int a,int b ,int &x,int &y)
    {
        if(a==0)
        {
            x=0;
            y=1;
        }
        else
        {
            exgcd(b%a,a,x,y);
            int swap;
            swap=x;
            x=y-(b/a)*x;
            y=swap;
        }
    }
    int main()
    {
    	a=12;b=30;
    	s=6;
    	exgcd(a,b,x,y);
    	printf("ax+by=```
    ");
    	printf("x=%d   y=%d",x,y);
    	return 0;
    }
    

    附件(网络资料):

    听说有非递归版!

    http://anh.cs.luc.edu/331/notes/xgcd.pdf

    http://math.cmu.edu/~bkell/21110-2010s/extended-euclidean.html

    如果你还是没有看懂

    下面有从《计算机程序设计艺术》转载的证明方法,仅供参考:

     证明(1):
      算法首次转到E2时,由上表,显然等式成立。
      步骤 E2,E3 并不会改变等式的正确性。
      所以只需要证明步骤 E4 不改变他们的正确性就可以了。
    
      执行 E4 之前,
          a'm + b'n = c    (*)
          am + bn = d      (**)
      成立。
      a'm + b'n = c = qd + r;
      a'm + b'n - q(am + bn) = r;
      (a' - qa)m + (b' - qb)n = r  (***)
    
      执行 E4 之后,c←d, d←r, t←a', a'←a, a←t-qa, t←b', b'←b, b←t-qb;
      所以
      (**)变为 a' + b' = c
      (***)变为 am + bn = d
      所以步骤 E4 不改变等式的正确性,得证。
    

    下面强势给出非递归版代码:(我也好像有点懂!)

    int exgcd(int m, int n, int &x, int &y) {
        if (n == 0) {
            x = 1; y = 0;
            return m;
        }
        int a, a1, b, b1, c, d, q, r, t;
        a1 = b = 1;
        a = b1 = 0;
        c = m; d = n;
    
        q = c/d; r = c%d;
        while (r) {
            c = d;
            d = r;
            t = a1;
            a1 = a;
            a = t - q * a;
            t = b1;
            b1 = b;
            b = t - q * b;
    
            q = c/d;
            r = c%d;
        }
        x = a; y = b;
        return d;
    }
    

    (以上代码为转载)

    相关练习题

    P1082 同余方程

    另一篇洛谷博客:

    简单的欧几里德拓展

    大佬的GCD是这样写的:

    ll GCD(ll a,ll b){while(b=a=b^=a%=b);return a;}

  • 相关阅读:
    Mysql:为什么用limit时,offset很大会影响性能
    [解决方案]未能找到路径“~in oslyncsc.exe”的一部分
    [经验分享]NuGet发布自己的Dll(类库包)
    [解决方案]使用百度富文本编辑器,编辑显示不了内容
    [解决方案]未能加载文件或程序集
    [经验分享]WebApi+SwaggerUI 完美展示接口
    [经验分享]Linux网络连接-VMware+CentOS 7
    [经验分享]WebAPI中返回类型JsonMessage的应用
    [解决方案]WebAPI+SwaggerUI部署服务器后,访问一直报错的问题
    [解决方案] 当 IDENTITY_INSERT 设置为 OFF 时
  • 原文地址:https://www.cnblogs.com/mudrobot/p/13330750.html
Copyright © 2020-2023  润新知