本文主要介绍数论中的欧几里得算法,线性方程及它们之间的关系。本文主要参考了《数论概论》,因此将本文当成这本书的读书笔记也未尝不可。
(本文正被完善中……)
欧几里得算法
问题:求60和22的最大公约数(两个数的最大公约数a, b是能够整除它们的最大数,记为gcd(a, b))。
因为这两个数比较小,所以我们完全可以通过肉眼观察出其最大公约数:
2
。那么对于(
225,120
)这一组数呢?我们可以分解两个数的因子:
225=32×52
120=23×3×5
然后求出所有数的约数(
a
的约数
divisor(a)
表示能够整除
a
的数):
divisor(225)={1,3,5,9,15,25,45,75,225}
divisor(120)={1,2,3,4,5,6,8,10,12,15,20,24,30,40,60,120}
它们的公约数
commonDivisor(225,120)={1,3,5,15}
其中最大的
15
就是它们的最大公约数(根据最大公约数的定义)。大功告成,总算让人松了一口气。按照这个方法,不论来什么样的一组数,我们都可以轻松的求它们的最大公约数了。等等,真的是这样吗?那么来看看这一组数:
(1160718174,316258250)
我的天,这题谁爱算谁算吧(溜~)。
下面介绍欧几里得算法,只要掌握了这种算法,就可以用极其快的速度算出两个数的最大公约数,就算是上面那两个天文数字也
OK
。不仅如此,欧几里得算法还很容易通过编程实现,那么就可以利用计算机的计算能力迅速的解决大多数(指的是有机会碰上的)最大公约数的问题,其代码量只有三行。
在介绍算法的具体过程之前,我打算先用文字描述一下这个算法,即使无法很好的说清楚这个算法,也让先有一个大体的概念。
欧几里得算法:可以用以下方法求a, b的最大公约数gcd(a, b):
- 计算
r=amodb
,然后令
a=b,b=r
。
- 重复步骤
1
,直到
r=0
,此时
b
就是答案。
下面我们将利用欧几里得算法计算
gcd(1160718174,316258250)
:
1160718174=3 ×316258250+211943424
316258250 =1 ×211943424+104314826
211943424 =2 ×104314826+3313772
104314826 =31×3313772 +1587894
3313772 =2 ×1587894 +137984
1587894 =11×137984 +70070
137984 =1 ×70070 +67914
70070 =1 ×67914 +2156
67914 =31×2156 +1078
(最大公约数)
2156 =2 ×1078 +0
我们只用了
10
次计算就将这两个天文数字的最大公约数计算出来了。下面用一种不严谨的方法证明这种计算方法是对的(为了证明的方便,这里仅以上面的数据为例,不做一般性的证明):
先证明
1078
是
1160718174
和
316258250
的公约数:
1078
能够整除
2156
(最后一个式子)
因为
1078
能够整除
1078
和
2156
,所以
1078
能够整除
67914
(倒数第二个式子)
……(以此类推)
因为
1078
能够整除
104314826
和
211943424
,所以
1078
可以整除
316258250
(第二个式子)
因为
1078
能够整除
316258250
和
211943424
,所以
1078
可以整除
1160718174
(第一个式子)
再证明
1078
是两数的公约数中最大的那个:
假设
d
为两数的任意公约数
因为
d
能够整除
1160718174
和
316258250
,所以
d
能够整除
211943424
(第一个式子)
因为
d
能够整除
316258250
和
211943424
,所以
d
能够整除
104314826
(第二个式子)
……(以此类推)
因为
d
能够整除
67914
和
2156
,所以
d
能够整除
1078
(倒数第二个式子)
那么
1160718174
和
316258250
的任意公约数都能整除
1078
,那么
1078
是两数的最大公约数。
简洁而神奇,这就是欧几里得算法。
扩展欧几里得算法
问题:求方程60x + 22y = gcd(60, 22)的一组解
这是个关于
x,y
的不定方程。我们观察这个方程。方程中有两个未知数,并且有一个奇怪的东西:
gcd(60,22)
。为什么这个方程长得如此奇怪呢?这要从一条叫贝祖定理的定理说起:
贝祖定理:设a,b是不全为零的整数,则存在整数x,y,使得ax + by = gcd(a,b)。
所以是因为这个方程的解一定存在,所以我们本着一颗“无聊的心”来考察一下这方程的如何求解。哈哈~
(事实上ax + by的结果一定是gcd(a, b)的整数倍,所以如果要讨论ax + by这种整数线性方程的话,就必然要讨论这个方程)
首先不管方程的解法如何,求出
gcd(60,22)
都是必须的。那我们在复习欧几里得算法的同时求一下
gcd(60,22)
:
设
a=60,b=22
(只是为了简洁),欧几里得算法的过程如下:
a=2×b+16
b=1×16+6
16=2×6+4
6=1×4+2
(最大公约数)
4=2×2+0
于是
gcd(a,b)
等于
2
。现在终于可以来解方程了。首先观察方程。显然,我们可以枚举
x,y
来求解,通过观察可以发现
−4a+11b=2
。但是对于更一般的
a
和
b
,用枚举的方法来解决问题就不一定有效了。这里就必须引入扩展欧几里得算法。同样,先介绍一下扩展欧几里得算法的大致步骤:
- 将欧几里得算法过程中的第一个式子中的
a, b, r
都用
a, b
表示
- 将第二个式子中的
a2, b2, r2
也用
a, b
表示
- 依次将第三,第四,…,第
m
式子中的
am, bm, rm
用
a, b
表示
- 将倒数第二条式子中的所有量用
a, b
表示,此时可以得到方程的解
具体的步骤如下(下面的每条式子同上述欧几里得算法的每条式子相对应):
16=a−2b
6=−a+3b
4=3a−8b
2=−4a+11b
上面的最后一条式子就向我们展示了解。这就是扩展欧几里得算法。因为其正确性是显然的,所以这里就不证明了。
问题:求方程ax + by = gcd(a, b)的通解
如果求
60x+22y=2
的解还不够满足的话,我们可以将这个问题的更一般的解找出来。将方程一般化后可以得到方程:
ax+by=g
,其中
g=gcd(a,b)
。我们尝试求出这条方程的所有解,也就是其通解。
首先,可以通过上述扩展欧几里得算法求出这条方程的一组解,我们可以将其记为
(x1,y1)
。
其次,我们可以先尝试求
g=1
的情况,也就是
a,b
互质(没有公共因子)的情况。显然,如果将
ax+by=1
的所有解
(x,y)
在平面直角坐标系中以点
(x,y)
的形式画出来,那么这些解一定落在直线
ax+by=1
上。以防有人不明白为什么这个方程的解集落在直线上,我们将方程变形为
y=−abx+1b
这个“斜截式”的方程就比较显然的呈现出一条直线了。那么方程的另一组解就可以表示为直线上的另一个坐标为整数的点
(x1+t,y1−abt)
其中
t
为某个神秘的我们暂时不需要知道是多少的整数。因为
g=gcd(a,b)=1
,所以 为了保证“
abt
是整数“,必须满足“t为b的倍数” 。否则若
b
既不能整除
a
又不能整除
t
,则
abt
就 不是整数。
好的,现在
t
是
b
的倍数了(之所以先讨论
g=1
, 目的就在于得到这个结论从而简化问题),那么t就可以表示为
k×b
,也就是
t=kb
,将
t
代入
(x1+t,y1−abt)
可得方程的通解的形式
(x1+kb,y1−ka)
其中
k
为任意整数,每个整数对应了方程的一组解。
然后,我们再讨论
g>1
的情况。先将方程
ax+by=g
变形:
agx+bgy=1
问题就转化成了上面一种情况,也就是
a′x+b′y=1,a′=ag,b′=bg,gcd(a′,b′)=1
的情况,那么套用前面的公式,通解就是
(x1+kbg,y1−kag)
问题:求方程ax + by = c的通解
问题:求方程ax + by = g的最小非负解