辗转相除法
求整数a,b的最大公约数gcd(a,b):
定理:gcd(a,b)=gcd(b,a%b)
证明:设a除以b得到的商和余数分别为k和r,则a=kb+r,r=a%b,设d为a,b公约数,则d一定整除r=a-kb,所以d是(b,a%b)的公约数。(a,b)和(b,a %b)公约数相同,最大公约数也一定相等。
根据该定理不断操作下去最终得到gcd(a,b)=gcd(c,0)=c。复杂度在O(log max(a,b))以内 。
递归:
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
非递归:
int gcd(int a,int b)
{
int r;
while(b)
{
r=a%b;
a=b;
b=r;
}
return a;
}
扩展欧几里得算法:
二元一次不定方程ax+by=c,求整数解(x,y)使该等式成立。其中a、b、c均为整数
a,b最大公约数为gcd(a,b),c若不为gcd(a,b)倍数,则方程无整数解,因为左式一定为gcd(a,b)倍数。
c为gcd(a,b)的倍数时,等式有解。通过计算使ax1+by1=gcd(a,b)成立的x1、y1,然后由x=(c/gcd(a,b))*x1,y=(c/gcd(a,b))*y1,得到x,y。
利用扩展的欧几里得算法递归求a*x+b*y=gcd(a,b)的一组整数解(设a>b)
b=0时,a*x=gcd(a,b)=a,得到x=1,y取0;
b≠0,设方程 ax1+by1=gcd(a,b); bx2+(a%b)y2=gcd(b,a%b);
方程二代入a%b=a-(a/b)*b得 :bx2+(a%b)y2=bx2+(a-(a/b)*b)y2=ay2+b(x2-(a/b)y2)
由欧几里得原理gcd(a,b)=gcd(b,a%b)得 ax1+by1= ay2+b(x2-(a/b)y2)
则可根据x2,y2求出x1=y2,y1=x2-(a/b)y2。
扩展欧几里得算法递归代码:
int extend_euclid(int a,int b,int& x,int& y)
{//返回最大公约数
if(b==0)
{
x=1;y=0;
return a;
}
else
{
int d=extend_euclid(b,a%b,y,x);
y-=(a/b)*x;
return d;
}
}
求解ax+by=c
bool linear_equation(int a,int b,int c,int &x,int &y)
{
int d=extend_euclid(a,b,x,y);
if(c%d)//c不是最大公约数的倍数,无解
return false;
int k=c/d;
x*=k;y*=k;
return true;
}