数学问题——拓展欧几里得算法

一、拓展欧几里得算法

  该算法用来解决这样一个问题:给定两个非零整数 a 和 b,求一组整数解 (x,y) ,使得 ax + by = gcd(a,b) 成立,其中 gcd(a,b) 表示 a 和 b 的最大公约数。

    • 递归边界:当 b 为 0 时,此时的 a 就等于 gcd,显然有 a*1+b*0=gcd 成立,此时 x=1,y=0;
    • 递推公式:设当计算 gcd(a,b) 时,有 ax1 + by1 = gcd 成立;而在下一步计算gcd(b,a%b) 时,又有 bx2 + (a%b)y2 = gcd 成立。有以下递推式:    

        $ \left\{\begin{matrix}x_{1} = y_{2}\\ y_{1} = x_{2} - (a/b)y_{2}\end{matrix}\right.  $

  代码如下:

 1 /*
 2     拓展欧几里得算法
 3 */
 4
 5 #include <stdio.h>
 6 #include <string.h>
 7 #include <math.h>
 8 #include <stdlib.h>
 9 #include <time.h>
10 #include <stdbool.h>
11
12 int x=0, y=0;
13 // 给定两个非零整数 a 和 b,求一组整数解 (x,y) ,使得 ax + by = gcd(a,b) 成立
14 int exGcd(int a, int b) {
15     if(b == 0) {    // 递归边界
16         x = 1;
17         y = 0;
18         return a;    // 返回最大公约数
19     }
20     int g = exGcd(b, a%b);
21     int temp = x;    // 存放 x 的值
22     x = y;            // 递推式
23     y = temp - a/b*y;
24     return g;        // g 是最大公约数
25 }
26
27 int main() {
28     int gcd = exGcd(4,3);
29     printf("4*%d + 3*%d = %d\n", x, y, gcd);
30
31     return 0;
32 }

  当 exGcd 函数结束时 x 和 y 就是所求的解。显然,在得到这样一组解之后,就可以通过下面的式子得到全部解

      $\left\{\begin{matrix} x^{‘} = x + \frac{b}{gcd}*K \\  y^{‘} = y - \frac{a}{gcd}*K \end{matrix}\right.$  (K 为任意整数)

  也就是说, x 和 y 的所有解分别以 b/gcd 与 a/gcd 为周期。那么其中 x 的最小非负整数解是什么呢?从直观上来看就是 x%(b/gcd) 。但是当 x 为负数时,x%(b/gcd) 也会得到一个负数,例如 (-15)%4=-3。考虑到即便 x 是负数,x%(b/gcd) 的范围也是在 (-b/gcd,0) ,因此对任意整数来说,$\left ( x\%\frac{b}{gcd} + \frac{b}{gcd} \right ) \% \frac{b}{gcd}$ 才是对应的最小非负整数解

二、方程 ax + by = c 的求解

  ax + by = c 存在解的充要条件是 c%gcd == 0,且一组解 (x,y) 等于 $\left ( \frac{cx_{0}}{gcd},\frac{cy_{0}}{gcd} \right )$。

  在得到这样一组解之后,就可以通过下面的式子得到全部解

      $\left\{\begin{matrix} x^{‘} =  \frac{cx_{0}}{gcd} + \frac{b}{gcd}*K \\  y^{‘} = \frac{cy_{0}}{gcd} - \frac{a}{gcd}*K \end{matrix}\right.$ (K 为任意整数)

  除此之外,可以得到和上面一样的结论,对任意整数来说,$\left ( x\%\frac{b}{gcd} + \frac{b}{gcd} \right ) \% \frac{b}{gcd}$ 是 ax+by=c 中 x 的最小非负整数解,一般来说可以让 x 取 $\frac{cx_{0}}{gcd}$,其中 x0 是 ax+by=gcd 的一个解。  

三、同余式 ax ≡ c(mod m) 的求解

  先解释什么是同余式。对整数 a、b、m 来说,入门 m 整除 a-b(即 (a-b)%m=0),那么就说 a 与 b 模 m 同余,对应的同余式为 a ≡ b(mod m),m 称为同余式的模。显然,每一个整数都各自与 [0,m) 中唯一的整数同余

  此处要解决的就是同余式 ax ≡ c(mod m) 的求解。根据同余式的定义,有 (ax-c)%m=0 成立,因此存在整数 y,使得 ax-c=my 成立。移项并令 y=-y 后即得 ax+my=c 。

  由上面的结论,$\left ( x,y \right ) = \left ( \frac{cx_{0}}{gcd\left ( a,m \right )},\frac{cy_{0}}{gcd\left ( a,m \right )} \right )$。

  至于全部解,有以下结论:

  设 a,c,m 是整数,其中 m≥1,则

    •  若 c%gcd(a,m) ≠ 0,则同余式方程 ax ≡ c(mod m) 无解。
    •  若 c%gcd(a,m) = 0,则同余式方程 ax ≡ c(mod m) 恰好有 gcd(a,m) 个模 m 意义下不同的解,且解的形式为      

        $x^{‘}=x+\frac{m}{gcd\left ( a,m \right )}*K$  

  其中 K = 0,1,... ,gcd(a,m)-1。

  

四、逆元的求解以及 (b/a)%m 的计算

  先解释什么是逆元(此处特指乘法逆元)。假设 a、b、m 是整数,m>1。且有 ab ≡ 1(mod m) 成立,那么就说 a 和 b 互为模 m 的逆元。通俗的说,如果两个数的乘积模 m 后等于 1,就称它们互为 m 的逆元。

  那么逆元有什么用处呢?当要计算 (b/a)%m 时,通过找到 a 模 m 的逆元 x,就有 (b/a)%m = (b*x)%m = ((b%m)*(x%m))%m 成立。这对于解决被除数 b 非常大的问题来说是非常实用的。

  由定义知,求 a 模 m 的逆元,就是求解同余式 ax ≡ 1(mod m),并且在实际使用中,一般把 x 的最小正整数解称为 a 模 m 的逆元。      

    • 如果 gcd(a,m) ≠ 1,那么同余式 ax ≡ 1(mod m) 无解,a 不存在模 m 的逆元。
    •  如果 gcd(a,m) ≠ 1,那么同余式 ax ≡ 1(mod m) 在 (0,m) 上有唯一解,直接使用拓展欧几里得算法解出 x 之后就可以用 (x%m + m)%m 得到 (0,m) 范围内的解,也就是所需要的逆元。    

  另外,如果 m 是素数,且 a 不是 m 的倍数,则还可以直接使用 费马小定理来得到逆元。

  费马小定理:设 m 是素数,a 是任意整数且 a $\not\equiv$ 0(mod m),则 am-1 ≡ 1(mod m)。

原文地址:https://www.cnblogs.com/coderJiebao/p/Algorithmofnotes16.html

时间: 2024-10-10 04:09:56

数学问题——拓展欧几里得算法的相关文章

对拓展欧几里得算法的一点理解

首先需要明确的一点是:这是一种算法,而非一个证明题. 算法的需求与数学证明题是不一样的,数学证明题要求严谨完整,而算法只需要证明我用到的某个的性质成立即可,相当于是“恰好发现了这一点”. 于是对于拓展欧几里得,我们是从欧几里得算法中发现了一个递推的性质,从而受到启发,产生猜想:可不可以利用递推求出二元一次方程的解? 我们把猜想建立在欧几里得算法之上,利用该算法的递推过程,贯穿该过程来得到想要解决问题的答案. 也就是说,我们仅仅需要证明我们得到的答案是正确的,而并非深刻挖掘欧几里得算法的过程. 拓

HDU - 1356 The Balance(拓展欧几里得算法的解空间结构)

题目: Description Ms. Iyo Kiffa-Australis has a balance and only two kinds of weights to measure a dose of medicine. For example, to measure 200mg of aspirin using 300mg weights and 700mg weights, she can put one 700mg weight on the side of the medicin

拓展欧几里得算法及代码实现

扩展欧几里得算法就是求: ax + by = gcd(a, b) 的一组整数解(x, y) 一.非递归的实现: 首先看a = 60, b = 22的情况: 表格左边是欧几里得算法,右边等式计算ax + by = gcd(a, b)的解 a = 2 × b + 16 16 = a - 2b b = 1 × 16 + 6 6 = b - 1 × 16 = b - 1 × (a - 2b) = -a + 3b 16 = 2 × 6 + 4 4 = 16 - 2 × 6 = (a - 2b) - 2 ×

如何使用拓展欧几里得算法求解模线性方程组(详解)

式子a≡b(mod n)称为a和b关于模n同余,它的充要条件是a-b是n的整数倍,即a-b=zn(其中z取整数). 而模线性方程组ax≡b(mod n)可以写成ax-b=zn(其中z取整数),移项可得 ax-zn=b,也即二元一次方程ax+by=c的形式,利用拓展欧几里得算法(extgcd)可以求解该方程是否有解及其一组解,并可根据该组解写出解系,进而求出一个特解,比如最小正整数解. 下面给出拓展欧几里得算法的程序. 1 typedef long long LL; 2 void extgcd(L

Sumdiv|同余|约数|拓展欧几里得算法

目录 Sumdiv|同余|约数|拓展欧几里得算法 Problem 分析 约数个数定理部分 约数和定理部分 等比数列部分 题目分析 扩展欧几里得算法部分 Code 呕,我吐了. Sumdiv|同余|约数|拓展欧几里得算法 Problem \[ 求A^{B}的所有约数之和 \ mod \ 9901\left(1\leqslant A,B \leqslant 5*10^{7}\right) \] 分析 约数个数定理部分 定理内容: 对于一个大于1的正整数n可以分解质因数: 则n的正约数个数为: 定理证

[数论]拓展欧几里得算法

欧几里得算法(辗转相除法) 用来求解最大公约数 1 int gcd(int a,int b){ 2 return b ? gcd(b,a%b) : a; 3 } 在 #include<algorithm> 中也可以直接调用 __gcd(a,b) 拓展欧几里得算法 求解不定方程: 引理:存在 x , y 使得 ax+by=gcd(a,b) 设a,b,c为任意整数,若方程ax+by=c的一组解是(x0,y0),则它的任意整数解都可以写成(x0+k*b/gcd(a,b),y0-k*a/gcd(a,b

欧几里得 &amp; 拓展欧几里得算法 讲解 (Euclid &amp; Extend- Euclid Algorithm)

欧几里得& 拓展欧几里得(Euclid & Extend-Euclid) 欧几里得算法(Euclid) 背景: 欧几里德算法又称辗转相除法,用于计算两个正整数a,b的最大公约数.                                                                                                                                               --百度百科 代码: 递推的代

欧几里得 &amp;amp; 拓展欧几里得算法 解说 (Euclid &amp;amp; Extend- Euclid Algorithm)

欧几里得& 拓展欧几里得(Euclid & Extend-Euclid) 欧几里得算法(Euclid) 背景: 欧几里德算法又称辗转相除法.用于计算两个正整数a.b的最大公约数. --百度百科 代码: 递推的代码是相当的简洁: int gcd(int a,int b) { return b == 0 ? a : gcd(b, a % b); } 分析: 方法说了是辗转相除法,自然没有什么好介绍的了. . Fresh肯定会认为这样递归下去会不会爆栈?实际上在这里是不会爆栈的,由于递归的层数是

拓展欧几里得算法求不定方程

对于 ax+by=gcd(a,b) 这样的方程,可以用扩展欧几里得算法exgcd求出一组通解. 根据欧几里得求gcd: gcd(a,b)=gcd(b,a%b) 可得 bx+(a%b)y=gcd(b,a%b) 根据 a%b=a−(a/b)∗b 可得 bx+ay−(a/b)b∗y=gcd(b,a%b) 化简得 ay+b(x−(a/b)y)=gcd(b,a%b) x′=y,y′=(x−(a/b)y) ax′+by′=gcd(b,a%b)<=>ax+by=gcd(a,b) 根据 gcd(a,0)=a