扩展的欧几里得算法

最近的密码学实验,要求模逆,以前都没认真的研究过扩展的欧几里得算法,就趁着这个机会,把扩展的欧几里得算法好好的研究了一番;

扩展的欧几里得算法的应用范围也很广泛:1.可以用来求解不定方程的解。2.可以用来求解模线性方程(线性同余方程)3.求解模的逆元。

由这个名称我们就可以得知,这个算法是对欧几里得算法的扩展,欧几里得算法是求两个数的最大公约数,而扩展的算法就是对上面式子的x,y进行求解。

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

下面给出这个算法的证明:

推理1:当b=0时,gcd(a,b)=a;此时,x=1,y=0;//推理1;

推理2:当a*b!=0时:

设a0*x0+b0*y0=gcd(a0,b0);这里的a0,b0,x0,y0都是其中的一个状态:

有欧几里得算法可得:

下一个状态:a1=b0,b1=a0%b0=a0-(a0/b0)*b0;

a1*x1+b1*y1=gcd(a1,b1);把前面得到的式子代入;

得:b0*x1+a0*y1-(a0/b0)*b0*y1=gad(a1,b1)=gcd(a0,b0);

由上面的过程可以得出:

x0=y1,y0=x1-(a0/b0)b0*y1 //推理2;

这样我们就得到了求解x0,y0的方法,x0,y0基于x1,y1;

上面利用的思想是基于递归的,所有我们就可以得出递归的程序,b=0就是递归的出口;

下面是递归的代码:

#include <iostream>
#include <cstdio>
int ext_gcd(int a,int b,int &x,int &y)
{
    if(b==0)//根据推理1
    {
        x=1;
        y=0;
        return a;
    }
    int r=ext_gcd(b,a%b,x,y);
    int t=y;//推理2
    y=x-(a/b)*y;
    x=t;
    return r;
}
int main()
{
    int a,b,x,y;
    scanf("%d%d",&a,&b);
    ext_gcd(a,b,x,y);
    printf("%d %d\n",x,y);
    return 0;
}

可以对照一下递归的欧几里得算法:

int gcd(int a,int b)
{
    if(b==0)
    return a;

    else return gcd(b,a%b);
 }

相当于就是在中间添加了求x,y的过程。

还可以利用非递归实现:(求模逆的过程),但是通过这种方法求得的模逆可能会出现负数,而模逆的定义要是最小正整数;

#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int gcd(int a,int b)//euclid
{
    int r;
    while(b!=0)
    {
        r=a%b;
        a=b;
        b=r;
    }
    return a;
}
void extend_euclid(int f,int d)//非递归版
{
    int x1,x2,x3;
    int y1,y2,y3;
    int q,t1,t2,t3,flag=0;
    x1=1,x2=0,x3=f;
    y1=0,y2=1,y3=d;
    while(1)
    {
        if(flag==1) break;
        if(y3==0)  x3=gcd(f,d);
        else if(y3==1)
        {
            y3=gcd(f,d);
            printf("%d\n",y2);
            flag=1;
        }
        q=x3/y3;
        t1=x1-q*y1;
        t2=x2-q*y2;
        t3=x3-q*y3;
        x1=y1,x2=y2,x3=y3;
        y1=t1,y2=t2,y3=t3;
    }
}
int main()
{
    int a,b;
    printf("输入要进行模逆运算的两个数:\n");
    scanf("%d%d",&a,&b);
    extend_euclid(a,b);
    return 0;
}

别人写的非递归程序:(比较精简)

int exgcd(int m,int n,int &x,int &y)
{
    int x1,y1,x0,y0;
    x0=1; y0=0;
    x1=0; y1=1;
    x=0; y=1;
    int r=m%n;
    int q=(m-r)/n;
    while(r)
    {
        x=x0-q*x1; y=y0-q*y1;
        x0=x1; y0=y1;
        x1=x; y1=y;
        m=n; n=r; r=m%n;
        q=(m-r)/n;
    }
    return n;
}

参考了http://www.acmerblog.com/extend-gcd-5610.html

时间: 2025-01-05 02:26:25

扩展的欧几里得算法的相关文章

day 2 - 4 最大公因数 与 (扩展)欧几里得算法

一.概念引入 GCD,全名Greatest common divisor(最大公因数). 我们以gcd(a,b)表示a与b的最大公因数. 二.欧几里得算法(又名辗转相除法) 用途: 求解gcd(a,b) 核心公式: gcd(a,b) = gcd(b,a mod b)  (其中a mod b > 0) 算法思路: (保证a>b) 当a是b的倍数时,a,b最大公约数为b: *PS:此时,a mod b = 0,即gcd(a,b) = gcd(b,a mod b) = gcd(b,0) = b,可用

回档|欧几里得算法和扩展欧几里得算法

欧几里得算法:用于求两个非负整数a.b的最大公因数(用gcd(a,b)表示).这里用d表示,假设d一定存在. 证明:由题设知d|a,d|b(d|a代表d能整除a,即a mod d=0) 设a=kb+r,这里k和r都是整数.则r=a mod b.        我们可以让a=n1d,b=n2d.则r=(n1-k*n2)d        ∴d|r  ∴gcd(a,b)=gcd(b,a mod b) 扩展的欧几里得算法: 对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数

扩展欧几里得算法的模板实现

我居然现在还记不住扩欧的板子,我太弱啦! 扩展欧几里得算法解决的是这样的问题: 给定一个不定方程组ax+by=gcd(a,b),求他的一组整数解 先给出实现代码 void exgcd(int a,int b,int &x,int &y) { if(!b) { x=1,y=0;//gcd(a,0)显然等于1*a-0*0=a return a; } int ans=exgcd(b,a%b,x,y); int tem=x; x=y; y-=tem-(a/b)*y; return ans;} 但实

欧几里得算法与扩展欧几里得算法_C++

先感谢参考文献:http://www.cnblogs.com/frog112111/archive/2012/08/19/2646012.html 注:以下讨论的数均为整数 一.欧几里得算法(重点是证明,对后续知识有用) 欧几里得算法,也叫辗转相除,简称 gcd,用于计算两个整数的最大公约数 定义 gcd(a,b) 为整数 a 与 b 的最大公约数 引理:gcd(a,b)=gcd(b,a%b) 证明: 设 r=a%b , c=gcd(a,b) 则 a=xc , b=yc , 其中x , y互质

POJ - 1061 青蛙的约会 (扩展欧几里得算法)

Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置.不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的.但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的.为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面. 我们把这

[NOI2002] 荒岛野人 扩展欧几里得算法

[问题描述] 克里特岛以野人群居而著称.岛上有排列成环行的M个山洞.这些山洞顺时针编号为1,2,-,M.岛上住着N个野人,一开始依次住在山洞 C1,C2,-,CN中,以后每年,第i个野人会沿顺时针向前走Pi个洞住下来.每个野人i有一个寿命值Li,即生存的年数.下面四幅图描述了一个有6个 山洞,住有三个野人的岛上前四年的情况.三个野人初始的洞穴编号依次为1,2,3:每年要走过的洞穴数依次为3,7,2:寿命值依次为4,3,1.     奇怪的是,虽然野人有很多,但没有任何两个野人在有生之年处在同一个

扩展欧几里得算法(extgcd)

相信大家对欧几里得算法,即辗转相除法不陌生吧. 代码如下: int gcd(int a, int b){ return !b ? gcd(b, a % b) : a; } 而扩展欧几里得算法,顾名思义就是对欧几里得算法的扩展. 切入正题: 首先我们来看一个问题: 求整数x, y使得ax + by = 1, 如果gcd(a, b) != 1, 我们很容易发现原方程是无解的.则方程ax + by = 1有正整数对解(x, y)的必要条件是gcd(a, b) = 1,即a, b 互质. 此时正整数对解

欧几里得算法以及扩展欧几里得算法(过河noip2005提高组第二题)

欧几里得算法:也被称作辗转相除法 gcd(a,b)=gcd(b,a%b); 终止条件a=gcd b=0; (gcd为a,b的最大公约数) 扩展欧几里得算法: a 和 b 的最大公约数是 gcd ,一定能够找到这样的 x 和 y ,使得: a*x + b*y = gcd 成立 我们只需要找到特殊解x0,y0; 则通解为 x = x0 + (b/gcd)*t    y = y0 – (a/gcd)*t 那如何求出下一组解呢 仿照欧几里得算法a=b,b=a%b代入. a%b = a - (a/b)*b

扩展欧几里得算法学习记

话说以前我刷noip题的时候就想学这个东西了,结果却一直拖到了现在…… 到了高二才会这种东西的我实在是个蒟蒻啊! 将扩展欧几里得算法之前,先讲讲欧几里得算法是什么:gcd(a,b)=gcd(b,a%b).很显然是不?但我们还是要给出证明(设r=a%b): 设x是a,b的一个公约数,由于存在k使得a=k*b+r,又由于a|x,b|x,则有r|x,所以x是b,r的公约数 设x是b,r的一个公约数,因为存在k使得a=k*b+r,且b|x,r|x,那么a|x,所以x是a,b的公约数 综上所述,a和b的所