欧几里德算法,即辗转相减或相除法.
也就是gcd(a,b)=gcd(b,a%b).
证明:
令a=kb+r,0<=r<b,即gcd(a,b)=gcd(kb+r,b).
因为gcd(a,b)|a且gcd(a,b)|b,
所以gcd(a,b)|r,即gcd(a,b)=gcd(b,r).
因为r能表示为a%b,
所以gcd(a,b)=gcd(b,a mod b).
注:|是整除符号,a|b代表a是b的因数.
这是欧几里德算法的详细证明.
代码实现如下:
int gcd(int a,int b){ if (!b) return a; else return gcd(b,a%b); } //递归版
inline int gcd(int a,int b){ int r; while (b){ r=a%b; a=b; b=r; } } //非递归版
几个性质:
1.gcd(a,b,c)=gcd(a,b-a,c-b),gcd(a,b,c,d)=gcd(a,b-a,c-b,d-c)等以此类推.
2.gcd(a1,a2,a3,...,an)=gcd(gcd(a1,a2,...,an/2),gcd(an/2+1,an/2+2,...,an)).
3.gcd(a1,a2,...,an,an+1)|gcd(a1,a2,...,an).
由性质3推得性质4:若gcd(a1,a2,...,an,an+1)≠gcd(a1,a2,...,an),则gcd(a1,a2,...,an,an+1)<=gcd(a1,a2,...,an)/2.
性质4的作用:假设a数组的所有数的范围是[1,l],那么gcd(a1),gcd(a1,a2),gcd(a1,a2,a3),...,gcd(a1,a2,...,an)中不相等的gcd最多只有log(L)个.
这些总不用证明了吧.
接下来扩展一下.
求一个方程的一组解:ax+by=c.
首先,这个方程有解的情况仅当c=gcd(a,b)时.
那么这组节该怎么求?
这么求:
ax+by=gcd(a,b)=gcd(b,a mod b).
设x0,y0是gcd(b,a mod b)=bx0+(a mod b)y0的一组解.
把a mod b看成a-a/b*b.
方程变为:bx0+ay0-a/b*b*y0=gcd(b,a mod b).
由于我们只求一组解,所以可以得出:
ax=ay0.
by=bx0-a/b*b*y0.
由此可得:
x=y0.
y=x0-a/b*y0.
所以在求解gcd的同时可以求解:
int ex_gcd(int a,int b,int &x,int &y){ if (!b){ y=0; x=1; return a; } int g=gcd(a,b,x,y),tmp=x; x=y; y=tmp-a/b*y; return g; }这是扩展欧几里德的过程.