Euclid
亦称辗转相除法
计算两个整数a,b的最大公约数
令a=qb+r,其中a,b,q,r都是整数
则有gcd(a,b)=gcd(b,r)
亦即gcd(a,b)=gcd(b,a%b)
Extend Euclid
令a,b不全为0,存在整数x,y,使得
gcd(a,b)=xa+yb(Bezouts identity)
LAME'S Throrem
用欧几里得算法计算两个正整数的最大公因子时,所需除法次数不会多于两个整数中较小的那个十进制数的倍数的五倍
Inference of LAME'S Throrem
求两个正整数a,b, a>b的最大公因子需要O(log₂a)³次的位运算
Inference of Extend Euclid
如果gcd(a,b)=1,则a,b互素
亦即,xa+yb=1,则a,b互素
证明
设a>b
推理1
显然当 b=0,gcd(a,b)=a。此时 x=1,y=0
推理2
ab不等于0 时
设 ax₁+by₁=gcd(a,b)
bx2+(a mod b)y2=gcd(b,a mod b)
根据朴素的欧几里德原理有
gcd(a,b)=gcd(b,a mod b)
则 ax₁+by₁=bx₂+(a mod b)y₂
即 ax₁+by₁=bx₂+(a-(a/b)*b)y₂=ay₂+bx₂-(a/b)*by₂
根据恒等定理得 x₁=y₂; y₁=x₂-(a/b)*y₂;
递归代码
int exgcd(int a,int b,int & x,int & y)
{
if(b == 0)
{//根据上面的推理1,基本情况
x = 1;
y = 0;
return a;
}
int r = exgcd(b, a%b, x, y);
//根据推理2
int t = y;
y = x - (a/b)*y;
x = t;
return r;
}
int main()
{
int x,y;
exgcd(47,30,x,y);
cout << "47x+30y=1 的一个整数解为: " << x << y;
return 0;
}
应用
1.求解不定方程
用Extend Euclid求解不定方程ax+by=c
bool linear_equation(int a,int b,int c,int &x,int &y)
{
int d=exgcd(a,b,x,y);
if(c%d)
return false;
int k=c/d;
x*=k; y*=k; //求得的只是其中一组解
return true;
}
2.求解模线性方程(线性同余方程)
用Extend Euclid求解同余方程ax≡b (mod n)
同余符号
a≡b(mod m)
两个整数a,b,若它们除以整数m所得的余数相等,则称a,b对于模m同余
读作a同余于b模m,或读作a与b关于模m同余
ax≡b(mod n)即为ax%n=b%n
对未知数x有解,当且仅当 gcd(a,n) | b (也就是 b % (gcd(a,n))==0 )。且方程有解时,方程有 gcd(a,n) 个解。
求解ax%n=b%n
ax-ny₁=b-ny₂
ax+n(y₂-y₁)=b
令y=y₂-y₁
即相当于求解 ax+ ny= b (x, y为整数)
模线性方程解集为等差数列,令公差为dx
那么有
a*x=b(mod n)
a*(x+dx)=b(mod n)
两式相减,得
a*dx%n= 0
a*dx就是a的倍数,也是n的倍数
即a*dx是a和n的公倍数,取a和n的最小公倍数,此时对应的dx最小
令gcd(a,n)=d,那么lcm(a,n)=(a*n)/d
即a*dx=a*n/d
dx=n/d
bool modular_linear_equation(int a,int b,int n)
{
int x,y,x0,i;
int d=exgcd(a,n,x,y);
if(b%d)
return false;
x0=x*(b/d)%n; //特解
for(i=1;i<d;i++)
printf("%d\n",(x0+i*(n/d))%n);
return true;
}
3.求解模的逆元
同余方程ax≡b (mod n),如果 gcd(a,n)=1,则方程只有唯一解
在这种情况下,如果 b=1,同余方程就是ax=1(mod n),gcd(a,n)=1
称求出的x为a的对模n乘法的逆元
对于同余方程ax=1(modn), gcd(a,n)=1的求解
就是求解方程ax+ny=1,x, y为整数
可用扩展欧几里德算法求出,原同余方程的唯一解就是用扩展欧几里德算法得出的x
Reference:http://www.cnblogs.com/frog112111/archive/2012/08/19/2646012.html