欧几里得和扩展欧几里得讲解(基础数论)


已知两个整数a,b,求a,b的最大公约数,我们有如下的方法:

1.循环i从mind(a,b)~1,第一个既能被a和b整除的i就是a和b的最大公约数。

2.辗转相减法

3.辗转相除法,即欧几里得。

算法1:暴力求解

int gcd(int a,int b)  
{
    int ans;
    for(int i = min(a,b); i > 0; i--)
    {
        if(a%i==0 && b%i==0)
        {
            ans = i;
            break;
        }
    }
    return ans;
}

暴力求解当a,b较大而且互素的时候,非常耗时。


算法2:辗转相减法

int gcd(int m,int n)
{
    if (m==n) return m;
    if(m<n) return gcd(n-m,m);
    return gcd(m-n,n);
}
辗转相减法是很不错的。


算法3:辗转相除法

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

递归写法真的贼简单,是我喜欢(❤ ω ❤)的。

虽然天天用辗转相除法,但是确没有证明过为什么这样是对的。

证明欧几里得算法:

假如我们要求整数a和b的最大公约数。无特殊声明,以下出现的小写字母都代表整数,

设 q = a/b(在此除法指整除) 是商,r = a%b 为余数,d = gcd(a,b),即a、b的最大公约数为d。

则  a = b*q + r

由于d是a和b的最大公约数,因此一定存在整数c1,c2使得a = c1*d  ,    b = c2*d

因为a = b*q + r ,

所以 r = a - b*q 

  = c1*d - c2*d*q

  = d*(c1-c2*q)

由于c1,c2,q全都是整数,所以c1-c2*q也是整数,从上面的式子我们可以看到r / d = c1-c2*q

由此可知d也是r的因子,因为d是b的因子,则d是b和r的公因子,但是现在需要证明d到底

是不是b和r的最大公因子呢?

继续往下证明。假设c是b和r的任一公因子,则b是c的倍数,r也是c的倍数,从a = b*q+r

可以看出a必然是c的倍数,所以c也是a,b的因子,但是a,b的最大公因子是d,所以c<=d.

又因为c是b和r的任一公因子,因此c可以是b和r的最大公因子,c又是小于等于d的。且

d是b和r的公因子,所以d就是b和r的最大公因子。

因此d = gcd(b,r).

综上所述: d = gcd(a,b) = gcd(b,r) = gcd(b,a%b)

上面的式子表示的就是一个递归的过程,递归结束的条件是0,这时最后的余数为0.


欧几里得算法推论:扩展欧几里得

若d = gcd(a,b),则有x和y使得ax+by = d

这一点我们可以通过逆推欧几里得算法得到。

我们知道欧几里得算法执行到最后:

a = gcd(a,b) = d,  b = 0

则存在 x1 = 1 ,  y1 = (任意数,因为b为0,不过我们通常取0) ,满足a*x1 + b*y1 = d 成立 

由于gcd(a,b) = gcd(b,r)


我们知道最后一步得到:

b*x1 + r*y1 = d;

r = a%b 得到下面的式子

b*x1 + a%b*y1 = d;

b*x1 + (a-a/b*b)*y1 = d

b*x1 + a*y1 - (a/b)*y1*b = d

a*y1 + (x1-(a/b)*y1)*b = d

解得:

x2 = y1       y2 = x1 - (a/b)*y1;

同理我们可以继续网上推,可以知道必定是存在解x,y使得ax+by=gcd(a,b)。

证必。


算法实现:在欧几里得算法上做小小的改进

int d,x,y;
///扩展欧几里得。
void extend_gcd(int a,int b)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        d = a;
        return;
    }
    extend_gcd(b,a%b);
    int temp = x;    ///先暂时存放一下x
    x = y;
    y = temp-a/b*y;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        extend_gcd(n,m);
        printf("%d %d %d",d,x,y);
    }
    return 0;
}


本文部分证明参考自《基础数论》这本书。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值