给定 a , b , c , d a,b,c,d a,b,c,d,求解 a x + b y = g c d ( a , b ) ax\ +by\ =\ gcd(a,b) ax +by = gcd(a,b)中的任意正数解 ( x , y ) (x,y) (x,y)
我们可以根据裴蜀定理,证明方程一定有解。
由于欧几里得算法 g c d ( a , b ) = g c d ( b , a % b ) gcd(a,b)\ =\ gcd(b,a\ \%\ b) gcd(a,b) = gcd(b,a % b),则有:
a x + b y = b x + ( a % b ) ∗ y ax\ +by\ =bx\ +\ (a\ \%\ b)*y ax +by =bx + (a % b)∗y
用除法代替取模,则: a x + b y = b x ′ + y ′ ( a − [ a / b ] ∗ b ) ax\ +by\ =bx'+y'(a-[a/b]*b) ax +by =bx′+y′(a−[a/b]∗b)
通过乘法分配律和结合律的运算可得: a x + b y = a y ′ + b ( x ′ − [ a / b ] ∗ y ′ ) ax+by=ay'+b(x'-[a/b]*y') ax+by=ay′+b(x′−[a/b]∗y′)
其中, x ′ x' x′和 y ′ y' y′是方程 b x + y ( a − [ a / b ] ∗ b ) = g c d ( b , a % b ) bx+y(a-[a/b]*b)=gcd(b,a\%b) bx+y(a−[a/b]∗b)=gcd(b,a%b)的解,用来借助这个已经求得的 x ′ x' x′和 y ′ y' y′结合已知的 a a a和 b b b推得现在的解 x , y . x,y. x,y.其中 a a a和 b b b不变。我们可以通过递归来求。
递归的边界:
a x + b y = g c d ( a , 0 ) ax+by=gcd(a,0) ax+by=gcd(a,0)时,即 b = 0 b=0 b=0时, x = 1 y = 0. x=1\ y=0. x=1 y=0.
#include
#include
#include
#include
using namespace std;
int x,y;
int exgcd(int a,int b)
{
if (b==0)
{
x=1;
y=0;
return a;
}
int n=exgcd(b,a%b);
int t=x;
x=y;
y=t-a/b*y;
return n;
}
int main(void)
{
int a,b;
cin>>a>>b;
cout<<exgcd(a,b)<<endl;//这里输出最大公约数
cout<<x<<' '<<y<<endl;//这个输出方程ax+by=gcd(a,b)的解
return 0;
}
根据裴蜀定理,我们可以得到如下方程的解:
a x + b y = c , g c d ( a , b ) ∣ c ax\ +\ by\ =\ c,\ gcd(a,b)\ |\ c ax + by = c, gcd(a,b) ∣ c
因此在代码实现上,我们递归到了边界是换一个处理,令 x = c / g c d ( a , b ) , y = 0 x\ =\ c/gcd(a,b),\ y\ =\ 0 x = c/gcd(a,b), y = 0。
代码实现和上述代码基本相似。
对于方程 a x + b y = c , g c d ( a , b ) ∣ c ax\ +\ by\ =\ c,\ gcd(a,b)\ |\ c ax + by = c, gcd(a,b) ∣ c来说,如果有一组解 ( x 0 , y 0 ) (x_0,y_0) (x0,y0),我们可以用含有 x 0 x_0 x0和 y 0 a y_0a y0a来解释这一个方程的通解。
我们可以通过相乘再相加抵消,来证明这一串代数式属于Exgcd算法的通解:
( x 0 + k ∗ b g c d ( a , b ) , y 0 + k ∗ a g c d ( a , b ) ) (x_0\ +\ k*\frac{b}{gcd(a,b)}\ \ \ \ \ \ ,\ \ \ \ \ \ y_0\ +\ k*\frac{a}{gcd(a,b)}) (x0 + k∗gcd(a,b)b , y0 + k∗gcd(a,b)a)
显然,两个数字乘上 a , b a,b a,b以后再相加,结果一定等于 x 0 + y 0 x_0+y_0 x0+y0 。 k k k取任意整数。
现在我们需要求解有关 x x x的线性同余方程: a ∗ x ≡ b ( m o d m ) a\ *\ x\ \equiv\ b\ (mod\ m) a ∗ x ≡ b (mod m)
变形一下,就变成了: a ∗ x − b ≡ 0 ( m o d m ) a*x\ -\ b\ \equiv\ 0\ \ \ (mod\ m) a∗x − b ≡ 0 (mod m)
然后我们就可以发现 a ∗ x − b a*x\ -\ b a∗x − b一定是 m m m的倍数,因此我们设是 m m m的 − y -y −y倍,则可以将同余式变形为等式:
a ∗ x − b = − y ∗ m ⟹ a ∗ x + y ∗ m = b a*x\ -b\ =\ -y*m\Longrightarrow a*x+y*m\ =\ b a∗x −b = −y∗m⟹a∗x+y∗m = b
现在我们就变形为了一个扩展欧几里得算法的形式,即可运用上述算法求出对应的解 x x x。
我们知道扩展欧几里得的通解形式是:
( x 0 + k ∗ b g c d ( a , b ) , y 0 + k ∗ a g c d ( a , b ) ) (x_0\ +\ k*\frac{b}{gcd(a,b)}\ \ \ \ \ \ ,\ \ \ \ \ \ y_0\ +\ k*\frac{a}{gcd(a,b)}) (x0 + k∗gcd(a,b)b , y0 + k∗gcd(a,b)a)
再结合线性同余方程的欧几里得式:
a ∗ x + y ∗ m = b a*x+y*m\ =\ b a∗x+y∗m = b
我们考虑对每一个 x x x求出通解:
我们知道了方程的通解,则另 P = m g c d ( a , m ) P\ =\ \frac{m}{gcd(a,m)} P = gcd(a,m)m,对于任意一个整数解 x 0 x_0 x0,则有最小正整数解: x = ( x % P + P ) % P x\ =\ (x\ \%\ P\ +\ P)\ \%\ P x = (x % P + P) % P
Exgcd和线性同余方程是一个数论的模型,要熟记结论,灵活应用。许多的扩展和变形要需要以这两个算法为根本。