线性方程定理
已知两个整数a,b。我们观察a的倍数加上b的倍数得到的所有可能的整数。也就是 a x + b y ax+by ax+by得到的所有整数,其中x与y可以为任意整数,注意x,y可以取到负值。
例如我们列出a=42,b=30的所有整数,通过观察发现所有的数都是6的倍数,这很好理解,因为42与30都可以被6整除, 42 x + 30 y = 6 ( 7 x + 5 y ) 42x+30y=6(7x+5y) 42x+30y=6(7x+5y)的每个数都是6的倍数。更一般的,显然形如 a x + b y ax+by ax+by的每一个数都可以被 g c d ( x , y ) gcd(x,y) gcd(x,y)整除,因为 g c d ( x , y ) gcd(x,y) gcd(x,y)可以整除a,b。
第二个观察是42与30最大公因数6出现在了表中。
我们这时可以假设一个断言:
有许多方法可以证明这是成立的,我们可以利用欧几里得算法构造出合适的x,y,这里将计算过程列成表格,顺便与欧几里得算法过程进行对比。
a = 2 ∗ b + 16 a=2*b+16 a=2∗b+16 | 16 = a − 2 b 16=a-2b 16=a−2b |
---|---|
b = 1 ∗ 16 + 6 b=1*16+6 b=1∗16+6 | 6 = b − 1 ∗ 16 6=b-1*16 6=b−1∗16 |
\, | = b − 1 ∗ ( a − 2 b ) =b-1*(a-2b) =b−1∗(a−2b) |
\, | = − a + 3 b =-a+3b =−a+3b |
16 = 2 ∗ 6 + 4 16=2*6+4 16=2∗6+4 | 4 = 16 − 2 ∗ 6 4=16-2*6 4=16−2∗6 |
\, | = ( a − 2 b ) − 2 ∗ ( − a + 3 b ) =(a-2b)-2*(-a+3b) =(a−2b)−2∗(−a+3b) |
\, | = 3 a − 8 b =3a-8b =3a−8b |
6 = 1 ∗ 4 + 2 6=1*4+2 6=1∗4+2 | 2 = 6 − 1 ∗ 4 2=6-1*4 2=6−1∗4 |
\, | = ( − a + 3 a ) − 1 ∗ ( 3 a − 8 b ) =(-a+3a)-1*(3a-8b) =(−a+3a)−1∗(3a−8b) |
\, | = − 4 a + 11 b =-4a+11b =−4a+11b |
4 = 2 ∗ 2 + 0 4=2*2+0 4=2∗2+0 | \, |
按这种方法我们每次都会获得形如
的等式。最终得到最后的非零余数,这就是 g c d ( x , y ) gcd(x,y) gcd(x,y),得解。
现在我们知道
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax+by=gcd(a,b)
ax+by=gcd(a,b)总有整数解(x,y),我们可以进一步讨论方程有多少个解以及怎么表示所有的解。
从特殊到一般,我们首先从互素的a,b开始,即让
g
c
d
(
a
,
b
)
=
1
gcd(a,b)=1
gcd(a,b)=1,假设(x1,y1)是
方程的一个解。通过x1减去一个b的倍数和y1加上一个a的相同的倍数,可得到其他解,换句话说,对于任何整数k,我们得到了新解 ( x 1 + k b , y 1 − k a ) (x_1+kb,y_1-ka) (x1+kb,y1−ka),通过计算
可验证这确实是解。
同样我们也可以通过解方程推导出答案,仍然观察 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1的情况,假设(x1,y1),(x2,y2)是方程的两个解,则有:
我们用y2乘第一个方程,用y1乘第二个方程,相减就消去了b,重新整理后得到
类似地,如果用x2乘以第一个方程,用x1乘以第二个方程,再相减便得到
如果令 k = x 2 y 1 − x 1 y 2 k=x_2y_1-x_1y_2 k=x2y1−x1y2,则得到
这表明第二个解是由第一个解得到的,通过取不同的k可以得到每一个解 ( x 1 + k b , y 1 − k a ) (x_1+kb,y_1-ka) (x1+kb,y1−ka)。
如果 g c d ( a , b ) > 1 gcd(a,b)>1 gcd(a,b)>1的情况呢?我们令 g = g c d ( a , b ) g=gcd(a,b) g=gcd(a,b)由欧几里得一定可以得出
至少有一个解(x1,y2)而g整除a,b,故(x1,y1)也是简单方程
的解,于是可以代入前面的方法得到解为 ( x 1 + k ∗ b g , y 1 − k ∗ a g ) (x_1+k*\frac{b}{g},y_1-k*\frac{a}{g}) (x1+k∗gb,y1−k∗ga)。
线性方程定理设a,b是非零整数, g = g c d ( a , b ) g=gcd(a,b) g=gcd(a,b)。方程
总是有一个整数解(x1,y1),它可由前面的欧几里得算法得出,则方程的每一个解可由
得出,其中k为任意整数。
这节我们证明了方程 a x + b y = g ax+by=g ax+by=g总是有解,这个事实很重要,我们在接下来的数论中将多次用到。
算法代码
模拟上面的证明过程
int Eucild(int a1,int b1,int &x,int &y)
{
int a=a1,b=b1;
int r=a%b;
x=1;
int n=0,m=1,q;
while(r)
{
q=a/b;
x=m-q*n;
m=n;n=x;
a=b;b=r;
r=a%b;
}
y=(b-x*a1)/b1;
return b;
}
但这并不是一个优秀的算法。(是我自己编的,太菜了)
接下来给出一个标准算法
对于一个方程
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax+by=gcd(a,b)
ax+by=gcd(a,b)来说,我们可以做一下推导:
设有
a
x
1
+
b
y
1
=
g
c
d
(
a
,
b
)
ax_1+by_1=gcd(a,b)
ax1+by1=gcd(a,b);
b
x
2
+
(
a
%
b
)
y
2
=
g
c
d
(
b
,
a
%
b
)
bx_2+(a\%b)y_2=gcd(b,a\%b)
bx2+(a%b)y2=gcd(b,a%b)
对于这个方程组我们需要知道x1,x2,y1,y2的关系,才能递归的解决这个问题。
观察
b
x
2
+
(
a
%
b
)
y
2
=
g
c
d
(
b
,
a
%
b
)
bx_2+(a\%b)y_2=gcd(b,a\%b)
bx2+(a%b)y2=gcd(b,a%b)这个式子其中
(
a
%
b
)
(a\%b)
(a%b)可以写为
a
−
⌊
a
b
⌋
∗
b
a-\lfloor\frac{a}{b}\rfloor*b
a−⌊ba⌋∗b。将括号打开合并a,b得
由于欧几里得算法的原理
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),我们将两式子联立,对比系数即可得到
x
1
=
y
2
,
y
1
=
x
2
−
⌊
a
b
⌋
∗
y
2
x_1=y_2,y_1=x_2−\lfloor ab\rfloor∗y_2
x1=y2,y1=x2−⌊ab⌋∗y2
这个递归的边界是什么呢?我们知道,当朴素欧几里得到达边界时,
g
c
d
(
a
,
0
)
=
a
gcd(a,0)=a
gcd(a,0)=a,那么边界条件就是对
a
∗
x
0
+
b
∗
y
0
=
a
a∗x_0+b∗y_0=a
a∗x0+b∗y0=a求解,很显然,此时x0=1,y0=0
int eucild(int a,int b,int& x1,int& y1)
{
if(!b)
{
x1=1,y1=0;
return a;
}
int x2,y2;
int d=exgcd(b,a%b,x2,y2);
x1=y2,y1=x2-(a/b)*y2;
return d;
}