欧几里得算法和扩展欧几里得算法
概述
本篇简要介绍欧几里得算法和扩展欧几里得算法
欧几里得算法
欧几里得算法就是辗转相除法,用于求两个数的最大公约数
欧几里得算法:
public static int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
欧几里得算法的证明:
前提:设gcd(a,b) 是 自然数 a 和 b 的最大公约数,a 除以 b 得到的商和余数分别为 p 和 q
即: a = b * p + q (1)
若a能被b整除,b就叫做a的约数,即b可以整除a
由上式可以看出 gcd(b,q) 可以整除a,也可以整除b 【a,b 都可以被gcd(b,q) 整除】,也就是说
即:gcd(b,q) 可以整除gcd(a,b)
根据q = a - b*q 同理可证 gcd(a,b) 可以整除 gcd(b,q)
可以知道 gcd(a,b) == gcd(b,q) == gcd(b,a%b)
因为 a%b一直在减小,最后就会化为 gcd(c,0) 0和c的最大公约数是c 求得结果为c
扩展欧几里得算法
扩展欧几里得算法是对欧几里得算法的扩展,用于求解二元一次方程的整数解
扩展欧几里得算法的实现主要归咎于 裴蜀定理
前提:a,b为整数,且gcd(a,b) = d,那么对于任何整数 x,y
那么: ax+by 一定是d的倍数
个人理解:若两个整数有最大公约数d,那么ax+by = d一定有解
那么应该如何 根据裴蜀定理得到 二元一次方程的解?
这里我们通过一组特解得到其他解
-
当 a%b == 0时
因为gcd(a,b) == d,则 a == d
这时令x1 = 1,y1 = 0,可以证明 ax1+by1 = d
-
当 a%b !=0时
b * x2+(a%b) *y2=gcd(b,a%b)
由 欧几里得定理 gcd(a,b) == gcd(b,a%b) 可得
b * x2+(a%b) *y2 == a * x1+b * y1
又带入 a % b = a - b(a/b) 可得
a * x1 + b * y1 = a * y2 + b (x2 - (a/b) * y2)
即:
x1 = y2 y1 = x2-(a/b) * y2 (x2,y2是特解)
这里得到了解的关系,接下来通过 1 的特解,就可以求得其他解:
static long d,x,y
public static void exgcd(long a, long b, long x, long y)
{
if(b == 0) {d = a, x = 1, y = 0;}
else
{
exgcd(b, a%b, d, y, x);
y -= x * (a / b);
}
}
注:方程 ax + by = 1 有解 当且仅当 整数a和b互素(gcd(a,b)= 1)
无解情况:
对于ax+by = d,d不是gcd(a,b)的倍数
ax + by = d求得的解的大小
|x| <= b且 |y| <= a
扩展欧几里得算法应用
- 求解不定方程 (ax+by=c 给出整数abc,求出xy整数解)
- 求解模线性方程(线性同余方程)
- 求解模的逆元
线性同余方程
给定整数a,b,m,求一个整数满足:a*x≡b(mod m)
a * x≡b(mod m)可以说明a*x-b始终是m的倍数,即a *x - b= -y *m => a * x + m * y = b
利用扩展欧几里得算法求得x和y使得 a * x + m * y = gcd(a,m)后,把x放大 b/gcd(a,m) 倍即可求出未知数x
int x1 = exgcd(a,m,d,x,y);
x = x*b/d;
模的逆元
b' b≡1(modn)
若 a 与 p 互素,则满足 ( a * x ) % p = 1的 x为 a的逆元。
构造得(k * p + 1)% p = 1(k为任意常数) ,联立 (a * x) % p = 1 可以求得a的逆元
可得扩展欧几里得形式:a * x + k * p = 1
exgcd(a, b,x, y);
x = (x % b + b) % b; //防止x%b出现负数