擴展歐幾里得算法


【轉載】http://blog.csdn.net/qq_34494458/article/details/52637193

一:歐幾里得算法(輾轉相除法)

                       基本算法:設a=qb+r,其中a,b,q,r都是整數,則gcd(a,b)=gcd(b,r),即gcd(a,b)=gcd(b,a%b)。

證明:

       a可以表示成a = kb + r,則r = a mod b

  假設d是a,b的一個公約數,則有

  d|a, d|b,而r = a - kb,因此d|r

  因此d是(b,a mod b)的公約數

  假設d 是(b,a mod b)的公約數,則

  d | b , d |r ,但是a = kb +r

  因此d也是(a,b)的公約數

  因此(a,b)和(b,a mod b)的公約數是一樣的,其最大公約數也必然相等,得證

算法實現:

int gcd(int a,int b) {             //遞歸算法  
    return b ? gcd(b, a%b) : a;  
}  
  
int gcd(int a, int b) {      //迭代算法  
    while(b) {  
        int c = a%b;  
        a = b;  
        b = c;  
    }  
    return a;  
}  

二   擴展歐幾里得算法:

 

               基本算法:對於不完全為 0 的非負整數 a,b,gcd(a,b)表示 a,b 的最大公約數,必然存在整數對 x,y ,使得 gcd(a,b)=ax+by。

 

   證明:設 a>b。

  1,顯然當 b=0,gcd(a,b)=a。此時 x=1,y=0;

  2,ab!=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;

  根據恆等定理得:x1=y2; y1=x2-(a/b)*y2;

      這樣我們就得到了求解 x1,y1 的方法:x1,y1 的值基於 x2,y2.

   上面的思想是以遞歸定義的,因為 gcd 不斷的遞歸求解一定會有個時候 b=0,所以遞歸可以結束。

//遞歸代碼  
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, y, x);  
   int t = x;  
   y = y - a/b*t;  
   return r;  
  }
   // 非遞歸算法  
int exgcd(int m, int n, int &x, int &y) {  
   int x1, y1, x0, y0;  
   x0 = 1; y0 = 0;  
   x1 = 0; y1 = 1;  
   x = 0; y = 1;  
   int r = m%n;  
   int q = (m-r)/n;  
   while(r) {  
       x = x0 - q*x1;  
       y = y0 - q*y1;  
       x0 = x1; y0 = y1;  
       x1 = x; y1 = y;  
       m = n; n = r; r = m%n;  
       q = (m-r)/n;  
   }  
   return n;  
}

劉汝佳的:

void gcd(int a, int b, int& d, int& x, int& y) {  
    if (!b) {d = a; x = 1; y = 0; }  
    else {gcd(b, a%b, d, y, x); y -= x*(a/b); }  
}  

上面求出的 x(當a>b時)都是最接近0的正整數。(不知道為什么)

 

 

擴展歐幾里德算法的應用主要有以下兩個方面:

(1)求解不定方程;

(2)求解模線性方程(線性同余方程)與逆元;

 

 

(1)求解不定方程;

  1.對於不定整數方程ax+by=m,若 m mod Gcd(a, b)=0,則該方程存在整數解,否則不存在整數解。

     證明:

   首先擴展歐幾里德主要是用來與求解線性方程相關的問題,所以我們從一個線性方程開始分析。現在假設這個線性方程為a*x+b*y=m,如果這個線性方程有解,那么一定有gcd(a,b) | m,即a,b的最大公約數能夠整除m(m%gcd(a,b)==0)。證明很簡單,由於a%gcd(a,b)==b%gcd(a,b)==0,所以a*x+b*y肯定能夠整除gcd(a,b),如果線性方程成立,那么就可以用m代替a*x+b*y,從而得到上面的結論,利用上面的結論就可以用來判斷一個線性方程是否有解。
  2.ax+by=Gcd(a, b) 兩邊同時乘以 m/Gcd(a, b)得a(x*m/Gcd(a, b))+b(y*m/Gcd(a, b))=m;

上面已經列出找一個整數解的方法,在找到 a*x+  b*y = Gcd(a, b)的一組解x0,y0后,不定方程ax+by=m的一組解滿足 x = m(x0)/gcd , y = m*(y0)/gcd;
所以通解為  x = m*(x0)/gcd + k*lcm/a , y = m*(y0)/gcd + k*lcm/b (其中k為任意整數);
證明:

      令a1=a/gcd(a,b),b1=b/gcd(a,b),m1=m/gcd(a,b)。那么x,y的一組解就是x0*m1,y0*m1,但是由於滿足方程的解無窮多個,在實際的解題中一般都會去求解x或是y的最小正數的值。以求x為例,又該如何求解呢?還是從方程入手,現在的x,y已經滿足a*x+b*y=m,那么a*(x+n*b)+b*(y-n*a)=m顯然也是成立的。可以得出x+n*b(n=…,-2,-1,0,1,2,…)就是方程的所有x解的集合,由於每一個x都肯定有一個y和其對應,所以在求解x的時候可以不考慮y的取值。取k使得x+k*b>0,x的最小正數值就應該是(x+k*b)%b,但是這個值真的是最小的嗎??如果我們將方程最有兩邊同時除以gcd(a,b),則方程變為a1*x+b1*y=m1,同上面的分析可知,此時的最小值應該為(x+k*b1)%b1,由於b1<=b,所以這個值一定會小於等於之前的值。在實際的求解過程中一般都是用while(x<0)x+=b1來使得為正的條件滿足,為了更快的退出循環,可以將b1改為b(b是b1的倍數),並將b乘以一個倍數后再加到x上。

代碼:

    //不定方程  
void linear_equation(int a, int b, int c, int &x, int &y) {  
    int d = exgcd(a, b, x, y);  
    if (c%d)  
        return ;  
    int k = c/d;  
    x *= k; y *= k; // 一組解  
    return ;  
}  

相關題目:poj2115 poj2142 poj1061。

 

(2)求解模線性方程(線性同余方程)與逆元;

        同余方程 ax≡b (mod n)對於未知數 x 有解,當且僅當 gcd(a,n) | b。且方程有解時,方程有 gcd(a,n) 個解。

           求解方程 ax≡b (mod n) 相當於求解方程 ax+ (-ny)= b, (x, y為整數)。

   //ax = b (mod n) 即 (ax) mod n = b mod n

 算法導論上有兩個定理:

  定理一:設d = gcd(a, n), 假定對整數x', y', 有d = ax' + ny', 如果d | b, 則方程ax = b(mod n)有一個解的值為x0, 滿足:、

      x0 = x'(b / d)(mod n)

  定理二:假設方程ax = b(mod n)有解, x0是方程的任意一個解, 則方程對模n恰有d個不同的解, 分別為: xi = x0 + i * (n / d), 其中 i = 1,2,3......d - 1

  有了這兩個定理, 解方程就不難了。

代碼:

   // 模線性方程  
bool modular_linear_equation(int a, int b, int n) {  
    int x, y, x0, i;  
    int d = exgcd(a, n, x, y);  
    if (b%d)  
        return false;  
    x0 = x*(b/d)%n; //特解  
    for(i = 0; i < d; i++)  
        printf("%d\n", (x0 + i*(n/d))%n);  
    return true;  
}  

相關題目  hdu1576.

同余方程ax≡b (mod n),如果 gcd(a,n)== 1,則方程只有唯一解。
      在這種情況下,如果 b== 1,同余方程就是 ax=1 (mod n ),gcd(a,n)= 1。
      這時稱求出的 x 為 a 的對模 n 乘法的逆元。
      對於同余方程 ax= 1(mod n ), gcd(a,n)= 1 的求解就是求解方程
      ax+ ny= 1,x, y 為整數。這個可用擴展歐幾里德算法求出,原同余方程的唯一解就是用擴展歐幾里德算法得出的 x 。

代碼:

 
ll inv(ll a, ll n) {  
    ll d, x, y;  
    d = exgcd(a, n, x, y);  
    return (d == 1) ? (x%n + n)%n : -1;  
}  

相關題目: hdu2115.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM