【数论】拓展欧几里得算法

写在前面

  这篇博客是我在【数论】对 算术基本定理 的研究 中的一部分

  • 拓展欧几里得算法

   现在已经有了a-b == GCD(a,b) * (n1-n2),那就可以再来个直接点的

  GCD(a,b) + (p*n1+q*n2) == GCD(a,b)

此处放到MOD群里面可以变形为求逆元素

  即p*a+q*b == GCD(a,b)

  想要求出一组p,q∈Z,满足上式

 

  首先套用欧几里得算法的逻辑:

    结合算术基本定理,有

      GCD(a,b) == P1min(a1,b1)P2min(a2,b2)......Pnmin(an,bn)

      a MOD b == P1a1-b1P2a2-b2......Pnan-bn(执行的条件为ai>=bi)

    则能得到GCD(a,b) == GCD(b,a MOD b)

    那么就有p*a+q*b == GCD(a,b) == GCD(b,a MOD b)

    这样就可以写一个递归函数,一层一层MOD下去

    这样化简,直到ai MOD bi == 0

    即p*GCD(a,b) == GCD(a,b),那么在最后一层里面p==1

所以在拓展欧几里得里面,bi==0这一层中,ai即为GCD(a,b)

  (到此为止和欧几里得算法一模一样,我甚至是复制的欧几里得算法)

 

  而如果想要求出p和q,那么有一个回溯的过程就好了

  如何回溯得到p和q呢?

  来找一下相邻的层数间pi和pi+1,qi和qi+1的关系

  因为有p*a+q*b == GCD(a,b)

  则在每一层中:

    GCD(a,b)

      == pi*a+qi*b

      == pi+1*b + qi+1*(a MOD b)

      == pi+1*b + qi+1*(a - (a/b)*b)

      == pi+1*b + qi+1*a - qi+1*(a/b)*b

      == qi+1*a + pi+1*b - qi+1*(a/b)*b

      == qi+1*a + (pi+1 - qi+1*(a/b))*b

  即每层中pi == qi+1qi == pi+1 - qi+1*(a/b)

  然后就可以回溯了!

  然后就能写出不返回gcd,单纯求出一组p,q的拓展欧几里得了!

C++:

 1 #include<bits/stdc++.h>
 2 #define OUT(x) cout<<#x<<":"<<x<<endl;
 3 
 4 using namespace std;
 5 
 6 int x,y;
 7 
 8 void exgcd(int a,int b)
 9 {
10     if(!b){x=1;y=0;}
11     else{
12         exgcd(b,a%b);
13         int tmp=x;
14         x=y;y=tmp-(a/b)*y;
15     }
16 }
17 
18 int main(int argc,char *argv[],char *enc[])
19 {
20     exgcd(12,17);
21     OUT(x);OUT(y);
22     return 0;
23 }

  上面这个版本是我写的,比较诡异,来个常见的版本

C++:

 1 #include<bits/stdc++.h>
 2 #define OUT(x) cout<<#x<<":"<<x<<endl;
 3 
 4 using namespace std;
 5 
 6 int x,y;
 7 
 8 int exgcd(int a,int b)
 9 {
10     if(!b){
11         x=1;y=0;
12         return a;
13     }
14     int ret=exgcd(b,a%b);
15     int tmp=x;
16     x=y;y=tmp-(a/b)*y;
17     return ret;
18 }
19 
20 int main(int argc,char *argv[],char *enc[])
21 {
22     OUT(exgcd(12,17));
23     OUT(x);OUT(y);
24     return 0;
25 }

  仔细感受一下其中的差别啦~

猜你喜欢

转载自www.cnblogs.com/Antigonae/p/10105911.html