【待纠错】扩展欧几里得算法的一种自顶向下实现

上一次发博客已然是将近四年前,疫情还没开始的时候。
在这段时间里我暂别了OI,但是兜兜转转还是回到了计算机这一我一直向往的领域。
去年这个时候也动笔尝试写过一篇博客,但是工程量似乎比我想象中的要大些,自然烂尾了。
但今天登录的时候意外发现这几年里我的文章零零星星地有人点赞收藏,甚至有人关注我,实在不胜感激。

请注意,这篇博客里的代码实现有些问题,请不要参考代码

言归正传,扩展欧几里得算法是在广义欧几里得除法,也就是辗转相除法的过程中得出裴祖定理 s ⋅ a + t ⋅ b = ( a , b ) s·a+t·b=(a,b) sa+tb=(a,b) s s s t t t的方法。
文中我会使用%表示求余

为什么辗转相除法可以得到s和t?

辗转相除法就是反复利用 a = q b + c , q ∈ Z a=qb+c,q\in\mathbb{Z} a=qb+c,qZ时, gcd ⁡ ( a , b ) = gcd ⁡ ( b , c ) \gcd(a,b)=\gcd(b,c) gcd(a,b)=gcd(b,c)这一定理计算 gcd ⁡ ( a , b ) \gcd(a,b) gcd(a,b)的过程。在实际应用中表现为 a = q b + r a=qb+r a=qb+r其中 q = ⌊ a b ⌋ , r = a % b q=\lfloor\frac{a}{b}\rfloor,r=a\%b q=ba,r=a%b再令 b , r b,r b,r代替 a , b a,b a,b进行运算,即 r i = q i ⋅ r i + 1 + r i + 2 r_{i}=q_i·r_{i+1}+r_{i+2} ri=qiri+1+ri+2
我们发现 r i + 2 = r i − q i + 2 ⋅ r i + 1 r_{i+2}=r_i-q_{i+2}·r_{i+1} ri+2=riqi+2ri+1,经过多次代换,我们可以将最终的 r n r_n rn q i q_i qi a , b a,b a,b的线性组合表示

如何得到s和t

我们探究这个过程的第一步 a = q 1 b + a % b a=q_1b+a\%b a=q1b+a%b
a % b = a − q 1 b a\%b=a-q_1b a%b=aq1b
s 1 a + t 1 b = a % b s_1a+t_1b=a\%b s1a+t1b=a%b s 1 = 1 , t 1 = − q 1 s_1=1, t_1=-q_1 s1=1,t1=q1
第二步则是
( b % ( a % b ) ) = b − q 2 ( a % b ) (b\%(a\%b))=b-q_2(a\%b) (b%(a%b))=bq2(a%b)
代换得
s 2 = − q 2 s 1 , t 2 = − q 2 t 1 + 1 s_2=-q_2s_1,t_2=-q_2t_1+1 s2=q2s1,t2=q2t1+1
所以我们得到了递推公式:
s 1 = 1 , t 1 = − q 1 s_1=1,t_1=-q_1 s1=1,t1=q1
s i = − q i s i − 1 , t i = − q i t i − 1 + 1 s_i=-q_is_{i-1},t_i=-q_it_{i-1}+1 si=qisi1,ti=qiti1+1

简略地编写程序如下:

#include<cstdio>
struct tri{
	int g, s, t;
};
tri gcd(int a, int b, int s, int t) {
	if(a % b == 0) return (tri){b, s, t};
	return gcd(b, a % b, -(a / b) * s, -(a / b) * t + 1);
}
int main() {
	int a, b; scanf("%d%d", &a, &b);
	if(a < b) b ^=a, a ^= b, b ^= a;//swap a, b
	tri ans = gcd(b, a % b, 1, -(a / b));
	printf("gcd of %d and %d is %d, while %d * %d + %d * %d = %d\n",
		a, b, ans.g,
		ans.s, a, ans.t, b, ans.s * a + ans.t * b
	);
	main();
}

这个程序的主体部分在 a < b a<b a<b时会造成错误的结果,推测可能与我 a , b , s , t a,b,s,t a,b,s,t分别对应 b , a % b , s , t b,a\%b,s,t b,a%b,s,t的偷懒传参方式有关。
这个方法中 s , t s,t s,t的计算是与 a , b a,b a,b的变化同向的,故而适合笔算。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值