欧几里得算法及其扩展以及运用

以下内容部分来自度娘,另一部分来自百度百科。
扩展欧几里德算法
liaoy这是本校一位学长关于扩展欧几里得的讲解,讲得很好,欢迎大家阅读

【介绍】

扩展欧几里德算法是用来在已知a, b求解一组x,y,使它们满足贝祖等式: ax+by = gcd(a, b) =d(解一定存在,根据数论中的相关定理)。扩展欧几里德常用在求解模线性方程及方程组中。

【欧几里得算法】

一、概述

欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数。其计算原理依赖下面的定理:
gcd函数就是用来求(a,b)的最大公约数的。
gcd函数的基本性质:
gcd( a , b )=gcd( b , a ) = gcd( -a , b )=gcd( |a| , |b| )

二、公式表述

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是a,b的一个公约数,所以我们将a换成 y * d,把b换成 x * d,则可以得到r=yd-kxd,变为r=(y-kx)*d,所以d | r)(可能是我自己太蠢了吧)
因此d是( b , a mod b)的公约数
假设d是( b , a mod b)的公约数,则
d | b , d |r ,但是a = kb +r(如上,我们可以把b和r换一下,则可以得出)
因此d也是(a,b)的公约数
因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证

【C++代码实现】

int gcd(int a,int b){return b?gcd(b,a%b):a;}

【pascal代码实现】

function gcd(a,b:longint):longint;
begin
    if b=0 then exit(a);
    gcd:=gcd(b,a mod b);
end;

【扩展算法】

对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在整数对 x,y ,使得 gcd(a,b)=ax+by。

【C++代码实现】

int gcd(int a,int b,int &x,int &y){
    if (b==0){
        x=1,y=0;
        return a;
    }
    int q=gcd(b,a%b,y,x);
    y-=a/b*x;
    return q;
}

【pascal代码实现】

function gcd(a,b:longint; var x,y:longint):longint;
var t:longint;
begin
    if b=0 then
        begin
            x:=1; y:=0;
            exit(a);
        end;
    gcd:=gcd(b,a mod b,y,x);
    y:=y-(a div b)*x;
end;

//上面两个程序最后返回的值是gcd(a,b)

###对求解 x,y的方法的理解

设 a>b
1 显然当 b=0,gcd(a,b)=a。此时 x=1,y=0
2 a>b>0 时
设 ax1+ by1= gcd ( a , b )
bx2 + ( a mod b )y2 = gcd ( b , a mod b );
根据朴素的欧几里德原理有 gcd ( a , b ) = gcd ( b , a mod b );
则: ax1 + by1 = bx2 + ( a mod b )y2;
/上面的bx2 + ( a mod b )y2中是指的递归的时候下一层的数,仔细想想在求gcd的时候是需要递归的/
ax1 + by1 = bx2 + ( a - [ a / b ] * b )y2=ay2 + bx2 -[a/b] * by2;
也就是 ax1 + by1 = ay2 + b( x2 - [ a / b ] * y2
根据恒等定理得:x1= y2; y1 = x2 - [ a / b ] * y2;
这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2.
上面的思想是以递归定义的,因为 gcd 不断的递归求解一定会有个时候 b=0,所以递归可以结束。
扩展欧几里德算法是用来在已知a, b求解一组x,y使得ax+by = Gcd(a, b) =d(解一定存在,根据数论中的相关定理)。扩展欧几里德常用在求解模线性方程及方程组中。
把这个实现和Gcd的递归实现相比,发现多了下面的x,y赋值过程,这就是扩展欧几里德算法的精髓。

例题

洛谷 P1082 同余方程
这道题是2012年提高组day2 t1
####题目描述
求关于 x 的同余方程 ax≡1 (mod b)的最小正整数解。

输入格式:
输入只有一行,包含两个正整数 a, b,用一个空格隔开。

输出格式:
输出只有一行,包含一个正整数 x0,即最小正整数解。输入数据保证一定有解。

输入样例#1:
3 10
输出样例#1:
7
【数据范围】

对于 40%的数据,2 ≤b≤ 1,000;

对于 60%的数据,2 ≤b≤ 50,000,000;

对于 100%的数据,2 ≤a, b≤ 2,000,000,000。

分析

看到这道题的数据范围后,应该能想得到普通的o(n)之类的做法是不行的,所以只能往数学方法上考,尽量是能够在O(log2 n)及其以下出结果的。然后我们看到题目中所给的同余方程,应该就能立马想到肯定是跟数论有关(前提以是学过)。这个时候如果还能知道上面所讲的扩展欧几里得算法,那就可以直接上代码了。

程序代码

#include
#include
#include
#include
#include
using namespace std;
int a,b,x,y;
void gcd(int a,int b,int &x,int &y){
    if(b==0){ x=1,y=0; return ; }
    gcd(b,a%b,y,x);
    y-=(a/b)*x;//详解见上面的证明
}
int main(){
    scanf("%d%d",&a,&b);
    gcd(a,b,x,y);
    printf("%d",(x+b)%b);
} 

你可能感兴趣的:(数论,gcd,NOIP,gcd)