普通的欧几里得算法依据是辗转相除法,也就是,比如求 a , b a,b a,b 的最大公约数, a , b a,b a,b 进行辗转相除直到 a − b a-b a−b 或者 b − a b-a b−a 等于0,证明此时的原先 a , b a, b a,b 的最大公约数就是当前的 a a a,例子如下:
a = 16, b = 6
a > b, a = a - b = 10
a > b, a = a - b = 4
b > a, b = b - a = 2
a > b, a = a - b = 2
a = b = 2 = gcd(a, b)
可见a > b必须减到a < b截至,
故多步的减法可以合成一个 %
int gcd(int a, int b) {
return !b ? a : gcd(b, a % b);
}
有了上面的了解,我们就可以知道,欧几里得算法的底层原理,那么思考下面一个问题,给出
a
,
b
a, b
a,b,求出一组特解
x
0
,
y
0
x_0, y_0
x0,y0 满足下面表达式。
a
∗
x
+
b
∗
y
=
g
c
d
(
a
,
b
)
a * x + b * y = gcd(a, b)
a∗x+b∗y=gcd(a,b)
同样的,我们根据辗转相除法的思路,当
b
=
0
b=0
b=0 的时候找到最大公约数,此时
a
∗
1
+
0
∗
y
=
g
c
d
(
a
,
0
)
=
a
a * 1 + 0 * y = gcd(a, 0) = a
a∗1+0∗y=gcd(a,0)=a,故此时的
x
=
1
,
y
=
0
x = 1, y = 0
x=1,y=0。
假如我们的递归如下:
int exgcd(int a, int b, int x, int y) {
if(!b) {
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x; // ?
return d;
}
?
?
? 处为什么可以那样写,我们假定当前层:
a
∗
x
+
b
∗
y
=
g
c
d
(
a
,
b
)
a * x + b * y = gcd(a, b)
a∗x+b∗y=gcd(a,b)
下一层:
b
∗
y
+
(
a
−
a
/
b
∗
b
)
∗
x
=
g
c
d
(
a
,
b
)
b * y + (a - a / b * b) * x = gcd(a, b)
b∗y+(a−a/b∗b)∗x=gcd(a,b)
化简:
a
∗
x
+
b
∗
y
−
a
/
b
∗
b
∗
x
=
g
c
d
(
a
,
b
)
a * x + b * y - a / b * b * x = gcd(a, b)
a∗x+b∗y−a/b∗b∗x=gcd(a,b)
a
∗
x
+
b
(
y
−
a
/
b
∗
x
)
=
g
c
d
(
a
,
b
)
a * x + b(y - a / b * x) = gcd(a, b)
a∗x+b(y−a/b∗x)=gcd(a,b)
对于一般方程,
a
∗
x
+
b
∗
y
=
c
a * x + b * y = c
a∗x+b∗y=c,当
g
c
d
(
a
,
b
)
∣
c
gcd(a, b) | c
gcd(a,b)∣c 时才有解,我们定义
d
=
g
c
d
(
a
,
b
)
d = gcd(a, b)
d=gcd(a,b) 此时的解是:
x
0
=
x
∗
c
/
d
x_0 = x * c / d
x0=x∗c/d,
y
0
=
y
∗
c
/
d
y_0 = y * c / d
y0=y∗c/d
对于特解
x
0
,
y
0
x_0, y_0
x0,y0 当
x
0
x_0
x0 移动
n
n
n 格:
x
=
x
0
+
n
x = x_0 + n
x=x0+n
(
x
0
+
n
)
∗
a
+
y
∗
b
=
d
(x_0 + n) * a + y * b = d
(x0+n)∗a+y∗b=d
y
=
y
0
−
a
/
b
∗
n
y = y0 - a / b * n
y=y0−a/b∗n
转化后:
x
=
x
0
+
b
∗
n
x = x_0 + b * n
x=x0+b∗n
y
=
y
0
−
a
∗
n
y = y_0 - a * n
y=y0−a∗n
发现
x
x
x 每次变化
b
b
b 个单位并不是最小单位,故通解如下:
x
=
x
0
+
b
/
d
∗
k
x = x_0 + b / d * k
x=x0+b/d∗k
y
=
y
0
−
a
/
d
∗
k
y = y_0 - a / d * k
y=y0−a/d∗k
通解得到之后,如果
x
>
0
x > 0
x>0 那么最小正整数解就是
x
%
(
b
/
d
)
x \% (b / d)
x%(b/d)。
否则最小正整数解就是
(
x
%
(
b
/
d
)
+
(
b
/
d
)
)
%
(
b
/
d
)
(x \% (b / d) + (b / d)) \% (b / d)
(x%(b/d)+(b/d))%(b/d)。
故最小正整数解就是
(
x
%
(
b
/
d
)
+
(
b
/
d
)
)
%
(
b
/
d
)
(x \% (b / d) + (b / d)) \% (b / d)
(x%(b/d)+(b/d))%(b/d)。