ioname  

欧几里得算法和扩展欧几里得算法

概述

本篇简要介绍欧几里得算法和扩展欧几里得算法

欧几里得算法

欧几里得算法就是辗转相除法,用于求两个数的最大公约数

欧几里得算法:

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一定有解

那么应该如何 根据裴蜀定理得到 二元一次方程的解?

​ 这里我们通过一组特解得到其他解

  1. 当 a%b == 0时

    因为gcd(a,b) == d,则 a == d

    这时令x1 = 1,y1 = 0,可以证明 ax1+by1 = d

  2. 当 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出现负数

posted on 2022-08-19 23:24  ioname  阅读(90)  评论(0编辑  收藏  举报