擴充套件歐幾里得演算法詳解
為了介紹擴充套件歐幾里得,我們先介紹一下貝祖定理:
即如果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的最大公因數
}
呼呼