下面直接使用简称exgcd就好。
先引入紫书上的一个经典问题,求直线方程ax+by+c=0的所有整数解。
我们先来看一个简单的,求ax+by=gcd(a,b)的一组整数解。额,看起来没啥变化。。。但实际上这样就有了固定的套路——exgcd。
放一段代码:
1 void exgcd(int a, int b, int &d, int &x, int &y) { 2 if (!b) {d = a; x = 1; y = 0;} 3 else {exgcd(b, a % b, d, y, x); y -= x * ( a / b);} 4 }
上述代码怎么得到的呢?其实里面还是有欧几里得算法的影子的,新问题是求解那个方程。显然当b=0时,x=1,y=0是一组解,接下来只需要找到每个解与上一解的关系就可以了。
这里说的一个一个解是针对欧几里得算法递归分层而言的。
设x',y'是方程bx+(a%b)y=d的一组解(同时d也是a和b的最大公约数),有d=bx+(a%b)y,a%b=a-[a/b]*b,整理可得d=ay'+b(x'-[a/b]*y')。
这样就有x=y',y=x'-[a/b]*y'。我们一步步推就能求出ax+by=gcd(a,b)的一组解。
那么其他解呢?假设我们已求出x,y是一组解,x',y'是另一组解,则ax+by=ax'+by',a(x-x')=b(y-y'),两边同除以gcd(a,b),得a'(x-x')=b'(y-y'),那么一定有a'|(y-y'),设y-y'=ka',可以得到x'=x-kb'。
也就是说,对于一组特解x0,y0来说,x0+kb',y0-ka'就可以表示所有整数解。然而我们并未使用ax+by=gcd(a,b)这一条件,因此对其他形如ax+by=c的方程也成立。
回到最初的问题,ax+by+c=0。我们可以先求出ax+by=gcd(a,b)的所有解,若gcd(a,b)|c,那么对于已求出的每组解,x*(c/gcd(a,b)),y*(c/gcd(a,b))就是该问题的所有解。
补充一点,exgcd求出那组特解是满足|x|+|y|最小的一组解。