欧几里德及扩展欧几里德

欧几里德算法,即辗转相减或相除法.

也就是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;
}
这是扩展欧几里德的过程.

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/79680600