1. 程式人生 > >擴充套件歐幾里得演算法詳解

擴充套件歐幾里得演算法詳解

為了介紹擴充套件歐幾里得,我們先介紹一下貝祖定理

           即如果a、b是整數,那麼一定存在整數x、y使得ax+by=gcd(a,b)。

換句話說,如果ax+by=m有解,那麼m一定是gcd(a,b)的若干倍。(可以來判斷一個這樣的式子有沒有解)

有一個直接的應用就是 如果ax+by=1有解,那麼gcd(a,b)=1;

要求出這個最大公因數gcd(a,b),我們最容易想到的就是古老悠久而又相當強大的輾轉相除法:

int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}

但是,對於上面的式子ax+by=m來說,我們並不僅僅想要知道有沒有解,而是想要知道在有解的情況下這個解到底是多少。

所以,擴充套件歐幾里得

        當到達遞迴邊界的時候,b==0,a=gcd(a,b) 這時可以觀察出來這個式子的一個解:a*1+b*0=gcd(a,b),x=1,y=0,注意這時的a和b已經不是最開始的那個a和b了,所以我們如果想要求出解x和y,就要回到最開始的模樣。

        初步想法:由於是遞迴的演算法,如果我們知道了這一層和上一層的關係,一層一層推下去,就可以推到最開始的。類似數學上的數學歸納法。

        假設當前我們在求的時a和b的最大公約數,而我們已經求出了下一個狀態:b和a%b的最大公因數,並且求出了一組x1和y1使得                          b*x1+(a%b)*y1=gcd

(注意在遞迴演算法中,永遠都是先得到下面一個狀態的值)

這時我們可以試著去尋找這兩個相鄰狀態的關係:

首先我們知道:a%b=a-(a/b)*b;帶入:

b*x1 + (a-(a/b)*b)*y1

= b*x1 + a*y1 – (a/b)*b*y1

= a*y1 + b*(x1 – a/b*y1) = gcd   發現 x = y1 , y = x1 – a/b*y1

這樣我們就得到了每兩個相鄰狀態的x和y的轉化,就可以在求gcd的同時對x和y進行求值了hiahia

-----------------------------------------------------------------我是分割線哇----------------------------------------------------------------------------

板子板子:

#include<iostream>
#include<cstdio>
#include<cmath>

using namespace std;

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);
    int temp=y;    //把x y變成上一層的
    y=x-(a/b)*y;
    x=temp;
    return r;     //得到a b的最大公因數
}

呼呼