(扩展)欧几里得算法

【欧几里得算法】

在介绍扩展欧几里得算法之前,我先简单介绍一下欧几里得算法

欧几里得算法又称辗转相除法,用于计算两个整数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了可以去洛谷交一下这道题,感觉洛谷的数据强一些

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/81134244