深入浅出讲扩展欧几里得-exgcd

扩展欧几里得(exgcd)

扩展欧几里得的典型应用是解决形如

a × x + b × y = c a\times x+b\times y=c a×x+b×y=c

的二元一次方程的解的存在性问题以及求出特解与通解。

解的存在性问题

其实我们可以通过辗转相减法观察出来, a , b a,b a,b辗转相减的时候相当于 a × x + b × y a\times x+b\times y a×x+b×y中的 x , y x,y x,y不断变化的过程。我们通过前面的知识知道,这一个过程后,一定能得出最大公约数,所以 a × x + b × y = g c d ( a , b ) a\times x+b\times y=gcd(a,b) a×x+b×y=gcd(a,b)一定有解,那么是否 g c d ( x , y ) ≠ c gcd(x,y)≠c gcd(x,y)=c时就无解呢?

首先我们知道 c c c g c d ( a , b ) gcd(a,b) gcd(a,b)的倍数才可能有解,因为左边一定含有质因子 g c d ( a , b ) gcd(a,b) gcd(a,b),左边等于右边,则右边也一定含有 g c d ( a , b ) gcd(a,b) gcd(a,b),因此我们可以通过两边同时除以 g c d ( a , b ) gcd(a,b) gcd(a,b)得到一个新的式子:

k 1 × x + k 2 × y = c / g , g c d ( k 1 , k 2 ) = 1 k_1\times x+k_2\times y=c/g,gcd(k1,k2)=1 k1×x+k2×y=c/g,gcd(k1,k2)=1

由辗转相减可得: k 1 × x + k 2 × y = 1 k_1\times x+k_2\times y=1 k1×x+k2×y=1一定有解。所以, k 1 × x + k 2 × y = c / g k_1\times x+k_2\times y=c/g k1×x+k2×y=c/g一定有解。

所以,当 c c c g c d ( a , b ) gcd(a,b) gcd(a,b)的倍数时,方程一定有解。

特解与通解

所以我们只要求形如:

a × x + b × y = g c d ( a , b ) a\times x+b\times y=gcd(a,b) a×x+b×y=gcd(a,b)

然后,将解扩大 c / g c d ( a , b ) c/gcd(a,b) c/gcd(a,b)倍就可以得出方程的解了。

观察式子本质就是 a a a b b b辗转相减的过程。假设已经求出了

( a − b ) × x 1 + b × y 1 = g c d ( a , b ) (a-b)\times x_1+b\times y_1=gcd(a,b) (ab)×x1+b×y1=gcd(a,b)

的解 x 1 , y 1 x_1,y_1 x1,y1,那么变换一下就可以得到

a × x 1 + b × ( y 1 − x 1 ) = g c d ( a , b ) a\times x_1+b\times (y_1-x_1)=gcd(a,b) a×x1+b×(y1x1)=gcd(a,b)

我们可以得出

x = x 1 , y = y 1 − x 1 x=x_1,y=y_1-x_1 x=x1,y=y1x1

得到了原方程的解,所以我们可以将原问题转化为一个规模更小的子问题。然后根据子问题的答案推出原问题的答案。考虑到这个辗转相减可以用辗转相除来替代,我们可以将求解原问题转化为求解

b × x 1 + a % b × y 1 = g c d ( a , b ) b\times x_1+a\% b\times y_1=gcd(a,b) b×x1+a%b×y1=gcd(a,b)

由:

a % b = a − a / b × b a\% b=a-a/b\times b a%b=aa/b×b

代入得:

b × x 1 + ( a − a / b × b ) × y 1 = g c d ( a , b ) b\times x_1+(a-a/b\times b)\times y_1=gcd(a,b) b×x1+(aa/b×b)×y1=gcd(a,b)

等价于:

a × y 1 + b × ( x 1 − a / b ∗ y 1 ) = g c d ( a , b ) a\times y_1+b\times (x_1-a/b*y_1)=gcd(a,b) a×y1+b×(x1a/by1)=gcd(a,b)

得到:

x = y 1 , y = x 1 − a / b ∗ y 1 x=y_1,y=x_1-a/b*y_1 x=y1,y=x1a/by1

因此,我们只需要一直缩小问题的规模,直到变成 g c d ( a , b ) × x + 0 × y = g c d ( a , b ) gcd(a,b)\times x+0\times y=gcd(a,b) gcd(a,b)×x+0×y=gcd(a,b),然后得到一组解 ( 1 , 0 ) (1,0) (1,0),在这组解反推回去,得到一组原方程的特解。该过程可以用一个函数来实现。

代码:

e x g c d exgcd exgcd

int exgcd(int a,int b,int &x,int &y){
	int d=a;
	if(b!=0){
		d=exgcd(b,a%b,x,y);
		x-=(a/b)*y;
		swap(x,y);
	}else{
		x=1,y=0;
	}
	return d;
}

函数执行完毕后,代码里的 ( x , y ) (x,y) (x,y)就是 a × x + b × y = g c d ( a , b ) a\times x+b\times y=gcd(a,b) a×x+b×y=gcd(a,b)的一组特解。通解的变化规律就是 x , y x,y x,y的值往相反的方向变化,比如 x x x变大一点, y y y变小一点,使得答案不变,设这个变化的最小单位为 d 1 , d 2 d_1,d_2 d1,d2

a × ( x + d 1 ) + b × ( y − d 2 ) = g c d ( a , b ) a\times (x+d_1)+b\times (y-d_2)=gcd(a,b) a×(x+d1)+b×(yd2)=gcd(a,b)

a × d 1 = b × d 2 a\times d_1=b\times d_2 a×d1=b×d2

两边同除 g c d ( a , b ) gcd(a,b) gcd(a,b) k 1 = a / g c d ( a , b ) , k 2 = b / g c d ( a , b ) k_1=a/gcd(a,b),k_2=b/gcd(a,b) k1=a/gcd(a,b),k2=b/gcd(a,b)

k 1 × d 1 = k 2 × d 2 k_1\times d_1=k_2\times d_2 k1×d1=k2×d2

此时, g c d ( k 1 , k 2 ) = 1 gcd(k_1,k_2)=1 gcd(k1,k2)=1,显然 d 1 = k 2 , d 2 = k 1 d_1=k_2,d_2=k_1 d1=k2,d2=k1,可得通解为:

( x + k × d 1 , y − k × a / g c d ( a , b ) ) (x+k\times d_1,y-k\times a/gcd(a,b)) (x+k×d1,yk×a/gcd(a,b))

特解的绝对值大小

我们通过递归函数的实现可以观察到,解的绝对值是跟 a , b a,b a,b的绝对值同一个级别的。(即传入与传出的数据不会相差太大,如传入的很小,传出的爆炸)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值