(擴充套件)歐幾里得演算法
【歐幾里得演算法】
在介紹擴充套件歐幾里得演算法之前,我先簡單介紹一下歐幾里得演算法
歐幾里得演算法又稱輾轉相除法,用於計算兩個整數a,b的最大公約數。
下面的 gcd(a,b)表示 a,b 的最大公約數,mod 是取餘,div 是整除
其中有一個定理:gcd(a,b)= gcd(b,a mod 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 ) 的公約數是一樣的,其最大公約數也必然相等,得證
所以說若我們不斷地這樣除下去,直到 a mod b 等於 0 時,答案就是 b
程式碼如下:
int gcd(int a,int b)
{
int r=a%b;
while(r!=0)
{
a=b;
b=r;
r=a%b;
}
return b;
}
【擴充套件歐幾里得演算法】
那麼接下來是我們的重頭戲——擴充套件歐幾里得演算法
定理:若 a,b 不全為 0,則存在整數 x 和 y,使得 ax + by = gcd(a,b)
有些問題要我們求出這樣的方程的一組整數解
推導過程如下:
若 ,那麼
我們可以找出一組 滿足
一直這樣下去(這是一個遞迴的過程),直到 時,此時 就是一組合法的解,再代回去就行了
程式碼如下:
void exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
【例題】
例題傳送門同餘方程
這道題主要是要把原問題轉換成 ax + by = 1 的形式,然後就可以用擴歐了
還有由於 x 要是正整數,所以輸出答案時我們要把它轉成正的,即 x = ( x + b ) % b
程式碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
void exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
int main()
{
int a,b,x,y;
scanf("%d%d",&a,&b);
exgcd(a,b,x,y);
printf("%d",(x+b)%b);
return 0;
}
另外,再推薦一道例題青蛙的約會,也是一道裸的模板題,A了可以去洛谷交一下這道題,感覺洛谷的資料強一些