扩展欧几里得算法(exgcd)

欧几里得算法

首先我们来回顾一下求解2个数的最大公约数(gcd,Greatest Common Divisor)的欧几里得算法:
这个算法的核心是 g c d ( a , b ) = g c d ( b , a   m o d   b ) gcd(a,b)=gcd(b,a \ mod \ b) gcd(a,b)=gcd(b,a mod b),即 a a a b b b的公约数等于 b b b a   m o d   b a \ mod \ b a mod b的公约数.
至于为什么,oi-wiki上有,我们就不证了,但为了理解这个公式,我们举个例子
g c d ( 3 , 5 ) = g c d ( 5 , 3 ) = g c d ( 2 , 3 ) = g c d ( 3 , 2 ) = g c d ( 1 , 2 ) = g c d ( 2 , 1 ) = g c d ( 1 , 1 ) = g c d ( 0 , 1 ) = g c d ( 1 , 0 ) gcd(3,5)=gcd(5,3)=gcd(2,3)=gcd(3,2)=\\gcd(1,2)=gcd(2,1)=gcd(1,1)=gcd(0,1)=gcd(1,0) gcd(3,5)=gcd(5,3)=gcd(2,3)=gcd(3,2)=gcd(1,2)=gcd(2,1)=gcd(1,1)=gcd(0,1)=gcd(1,0)
然后你会发现,我们将要用1去模0了,但这显然是没有意义的*(a模b的定义为a除以b的余数).并且,1和0是没有公约数的(0没有任何约数),那么我们的程序好像就无法继续进行了.我们又观察到,5和3因为互质,最大公约数是1,恰好是当b=0的时候a的值.那么,其他的数进行gcd操作也会有这样的性质吗?

再来个例子
g c d ( 4 , 2 ) = g c d ( 0 , 2 ) = g c d ( 2 , 0 ) gcd(4,2)=gcd(0,2)=gcd(2,0) gcd(4,2)=gcd(0,2)=gcd(2,0)
好像确实是这样的!我们只需输出当b等于0时a的值即可!

实际上,当b=0时,就代表着前一步的a%b==0,也就是 b ∣ a b|a ba,那么我们的最大公约数显然就是b(下一步的a)了.

*如果你编译运行1%0这段代码,编译器报错[Warning] division by zero [-Wdiv-by-zero],程序RE

这样就可以写出代码:

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

在进入下一部分前,我们先来分析一下这个算法的复杂度.细心的读者已经发现了,上面的例子中有些操作是无效的,他们仅仅交换了a和b的位置,但对于程序运行来说,这是必需的.但他们的数量显然小于等于有效操作的数量,对于时间复杂度的分析来说可以略去.

回顾到取模这个运算,在正数意义下它的代码可以写成这样(你是否知道负数的取模运算?可以参考这篇文章):

while(a>b) a-=b//=a%b

实际上,G++中实现的取模不是这么简单.具体来说,若 a = q b + r

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值