輾轉相除法
求整數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;
}