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

(擴充套件)歐幾里得演算法

【歐幾里得演算法】

在介紹擴充套件歐幾里得演算法之前,我先簡單介紹一下歐幾里得演算法

歐幾里得演算法又稱輾轉相除法,用於計算兩個整數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)

有些問題要我們求出這樣的方程的一組整數解

推導過程如下:

若 b\neq 0 ,那麼那麼 gcd(a,b)=gcd(b,a \; mod\; b)

我們可以找出一組 x',y' 滿足 bx'+(a\; mod\; b)y'=gcd(b,a\; mod\; b)

\therefore ax+by=bx'+(a\; mod\; b)y'

\because a\; mod \; b=a-\left \lfloor \frac{\mathrm{a} }{\mathrm{b}} \right \rfloor b

\therefore ax+by=ay'+b(x'-\left \lfloor \frac{a}{b} \right \rfloor y')

\therefore x=y',y=x'-\left \lfloor \frac{a}{b} \right \rfloor y'

一直這樣下去(這是一個遞迴的過程),直到 b=0 時,此時 x=1,y=0 就是一組合法的解,再代回去就行了

程式碼如下:

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了可以去洛谷交一下這道題,感覺洛谷的資料強一些