相信大家都知道欧几里得法(辗转相除)求两个数的
g
c
d
(
最大公因数
)
gcd(最大公因数)
gcd(最大公因数)
根据这个算法的公式是
欧几里得
g c d ( a , b ) = g c d ( b , a gcd(a,b)=gcd(b,a gcd(a,b)=gcd(b,a% b ) b) b)
证明:
若r = a%b,则a可以表示成
r
=
a
−
k
∗
b
,
(
k
=
a
/
b
)
r=a -k*b, (k=a/b)
r=a−k∗b,(k=a/b)
假设
d
d
d是
a
,
b
a,b
a,b的一个公约数,
则有a%d=0, b%d=0,
设
a
=
x
∗
d
a = x*d
a=x∗d ,
b
=
y
∗
d
b = y*d
b=y∗d,
x
,
y
x,y
x,y为整数
而
r
=
a
−
k
∗
b
=
x
∗
d
−
k
∗
y
∗
d
=
(
x
−
k
∗
y
)
∗
d
r = a - k*b = x*d-k*y*d = (x-k*y)*d
r=a−k∗b=x∗d−k∗y∗d=(x−k∗y)∗d
因为
x
−
k
∗
y
x-k*y
x−k∗y是整数,所以
r
r
r是
d
d
d的倍数,
r
r%d=0
r
因此
d
d
d是(b,a % b)的公约数
证毕
拓展欧几里得
实现
解一组整数
x
,
y
,
使得
a
∗
x
+
b
∗
y
=
G
c
d
(
a
,
b
)
解一组整数x,y,使得a*x+b*y = Gcd(a,b)
解一组整数x,y,使得a∗x+b∗y=Gcd(a,b)
g
c
d
(
a
,
b
)
=
a
x
+
b
y
gcd(a,b)=ax+by
gcd(a,b)=ax+by
g
c
d
(
b
,
a
m
o
d
b
)
=
b
x
′
+
(
a
−
a
/
b
∗
b
)
y
′
gcd(b, a mod b)=bx'+(a-a/b*b)y'
gcd(b,a mod b)=bx′+(a−a/b∗b)y′
a
x
+
b
y
=
b
x
′
+
(
a
−
a
/
b
∗
b
)
y
′
ax+by=bx'+(a-a/b*b)y'
ax+by=bx′+(a−a/b∗b)y′
整理可得 :
x
=
y
′
,
y
=
x
′
−
(
a
/
b
)
y
′
x=y',y=x'−(a/b)y'
x=y′,y=x′−(a/b)y′
然后对于这个式子就可以递归求解了,显然在
b
=
0
b=0
b=0时
x
=
1
,
y
=
0
x=1,y=0
x=1,y=0,然后就可以返回地去求了
应用拓欧(关于 a x + b y = c ax+by=c ax+by=c)
判定是否有解
从上可知,当 c = = g c d ( a , b ) ∗ k c==gcd(a,b)*k c==gcd(a,b)∗k,那么就一定有解,反之就无解
求通解
我们先可以就特殊解,因为C是gcd(a,b)的倍数于是,原来的方程就可以传化为
a
x
+
b
y
=
c
=
>
a
x
/
d
+
b
y
/
d
=
g
c
d
(
a
,
b
)
ax+by=c => ax/d+by/d=gcd(a,b)
ax+by=c =>ax/d+by/d=gcd(a,b)就在原来的答案上/d就好
原方程的解有无限多组,因为满足下面式子:
a
∗
(
x
+
k
∗
b
)
+
b
∗
(
y
−
k
∗
a
)
=
c
a*(x+k*b)+b*(y-k*a)=c
a∗(x+k∗b)+b∗(y−k∗a)=c (化简之后一些可以抵消)
k
k
k为整数
于是我们得到
a
x
+
b
y
=
c
ax+by=c
ax+by=c的通解:
x
=
x
′
∗
c
/
d
+
k
∗
b
/
d
x=x'*c/d+k*b/d
x=x′∗c/d+k∗b/d
y
=
y
′
∗
c
/
d
−
k
∗
a
/
d
y=y'*c/d-k*a/d
y=y′∗c/d−k∗a/d
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
template <typename T>
inline void _read(T& x){
char ch=getchar();bool sign=true;
while(!isdigit(ch)){if(ch=='-')sign=false;ch=getchar();}
for(x=0;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+ch-'0';
if(!sign)x=-x;
}
int x,y;
int extended_gcd(int a, int b) { //ax+by=gcd(a,b)
int r, tmp;
if (b==0) { x = 1; y = 0; return a; }
r = extended_gcd(b, a % b);
tmp=x; x=y; y =tmp - a / b * y;
return r;
}
int main(){
int a,b,c;
cin>>a>>b>>c; //求ax+by=c的一组解
int d=extended_gcd(a,b);
if(c%d!=0){
puts("-1");
return 0;
}
else {
cout<<x*c/d<<" "<<y*c/d<<endl;//输出一组解
for(int k=1;k<=10;k++){
int x1,y1;
x1=x*c/d+k*b/d; //通解
y1=y*c/d-k*a/d;
cout<<x1<<" "<<y1<<endl;
}
}
}
应用拓欧(解模线性方程)
a ≡ b (mod n)的含义是a和b关于模n同余,即a mod n==b mod n
a ≡ b (mod n)的充要条件是a-b是n的整数倍
这样,ax ≡ b (mod n)可以解释成:ax-b是n的整数倍,设这个倍数为y,
则ax-b=ny,移项得ax-ny=b,这恰好是一个二元一次不定方程。
用扩欧就可以解决。