提到扩展欧几里德算法,先简要介绍下欧几里德算法,又称展转相除法,用于计算两个整数a和b的最大公约数(Greatest Common Divisor(GCD))。算法
为证实gcd(a,b)=gcd(b,a mod b),只需证实
(1)gcd(a,b) | gcd(b,a mod b)
设d=gcd(a,b) 则d|a且d|b
a mod b=a-qb (设q=[a/b])
由d|ax+by 则d|a mod b
因此d| gcd(b,a mod b)
(2)gcd(b,a mod b) | gcd(a,b)
设d=gcd(b,a mod b)
则d|b且d|a mod b
a=qb+(a mod b) (q=[a/b])
得d|a
因此d|gcd(a mod b)ide
求解a和b的最大公约数中,a能够表示为kb+r,则r =a mod b,假设d是a和b的一个公约数,则有d|a,d|b,r = a - kb,所以d|r(由于d是a的约数,又是b的约数,因此也是他们的多项式的约数),因此d是(b,a mod b)的公约数。因此在这不断代换中,a 必然>b,每次将a换成b,b换成amod b, a ,b 不断减少。直到b为0时,此时a为他们的最大公约数。oop
1 int euclid(int a,int b) 2 { 3 if (b==0) 4 return a; 5 else 6 return euclid(b,a%b); 7 }
而扩展欧几里德算法是用来求解已知a,b,求一组x,y使得a * x + b * y =Gcd(a,b)(这个解必定存在,数论定理)spa
由于Gcd(a,b)=Gcd(b,a%b),因此a * x + b * y = Gcd(a,b) = Gcd(b,a%b)。得b * x + (a%b)*y = b * x + (a - a/b*b)*y,这里的((a - a/b*b)*y)不可贵出,以前是a%b。如今我想获得这个数,怎么来呢。首先a/b,获得一个整数,在a!=b的状况下,这个整数再乘以b以后是不等于a的。因此余数就是这里的差值。即a - a/b*b。若是a==b,那么Gcd==a==b。继续,b * x + (a%b)*y = b * x + (a - a/b*b)*y。展开得b*x + a*y - a/b*b*y,合并得a*y + b*(x-a/b*y).这样,由于a,b都在减少,当b=0时,能够得出x=1,y=0,此时递归回去能够求出x,y。code
1 int extended_gcd(int a, int b, int &x, int &y) 2 { 3 int ret, tmp; 4 if (!b) 5 { 6 x = 1; 7 y = 0; 8 return a; 9 } 10 ret = extended_gcd(b, a % b,x, y); 11 tmp = x; 12 x = y; 13 y = tmp - a / b * y; 14 return ret; 15 } 16
对于方程a * x + b * y=c,该方程等价于a*c ≡ c(mod b);有整数解的充要条件是 c % gcd(a,b)==0。(定理)blog
因此方程 a*x+b*y=n;咱们能够先用扩展欧几里德算法求出一组x0,y0。即 a * x0 + b * y0 = Gcd(a,b);递归
而后两边同时除以Gcd(a,b) ,再乘以n。这样就获得了方程 :a * x0 * n / Gcd(a,b) + b * y0 * n / Gcd(a,b) =n;从而求出一个解get
经过扩展欧几里德求的是ax + by = Gcd(a, b)的解,令解为(x0, y0),代入原方程,得:ax0 + by0 = Gcd(a, b),
若是要求ax + by = c = Gcd(a, b)*c',能够将上式代入,得:
ax + by = c = (ax0 + by0)c',则x = x0c', y = y0c', c' = c / Gcd(a,b)
这里的(x, y)只是这个方程的其中一组解,x的通解为 { x0c' + k*b/Gcd(a, b) | k为任意整数 },y的通解能够经过x通解的代入得出io
若gcd(a,b)=1,即a、b互质,且x0,y0为a*x+b*y=n的一组解,则该方程的任一解可表示为:x=x0+b*t,y=y0-a*t;且对任一整数t,皆成立。
这样咱们就能够求出方程的全部解了,但实际问题中,咱们每每被要求去求最小整数解,因此咱们就能够将一个特解x。令t=b/gcd(a,b)=1,特解x=(x%t+t)%t;event
poj题目连接: