式子a≡b(mod n)称为a和b关于模n同余,它的充要条件是a-b是n的整数倍,即a-b=zn(其中z取整数)。
而模线性方程组ax≡b(mod n)可以写成ax-b=zn(其中z取整数),移项可得
ax-zn=b,也即二元一次方程ax+by=c的形式,利用拓展欧几里得算法(extgcd)可以求解该方程是否有解及其一组解,并可根据该组解写出解系,进而求出一个特解,比如最小正整数解。
下面给出拓展欧几里得算法的程序。
1 typedef long long LL; 2 void extgcd(LL a, LL b, LL &d, LL &x0, LL &y0) 3 { 4 if(b == 0){ 5 d=a;x=1;y=0; 6 } 7 else{ 8 extgcd(b,a%b,d,y,x); 9 y -= x*(a/b); 10 } 11 }
其中a,b是系数,d表示a,b的最大公约数,x0,y0表示一组特解。
由gcd(a,b)= gcd(b,a%b)
得ax0 + by0 = gcd(a, b) = gcd(b, a%b) = bx1 + (a%b)y1
其中a%b又可以写成a-a/b*b,
故又=bx1 + (a-a/b*b)y1
整理得 ay1 + b(x1-a/b*y1)
由系数相等的x0=y1,y0=(x1-a/b*y1);那么只要求出x1和y1即可求得x0和y0,故向下递归求x1,y1,如此递归一直求到gcd(an, 0) = an*xn + 0 * yn时,令xn=1,yn=0可满足该式,因为an*1+0*0=an=gcd(an, 0)。之后递归回退,直至求出x0,y0,而d也即a和b的最大公约数。
下面说如何判断是否存在整数解。
将ax+by=c两边同时除以d可得
a/d*x+b/d*y=c/d,因为d为a和b的最大公约数,所以a/d和b/d均为整数,故要求x和y的整数解,c/d必须为整数,否则无整数解。
综上,有如下结论:设a,b,c为任意整数,d=gcd(a,b),d=ax+by,若c是d的倍数,则存在整数解,否则不存在整数解。
下面说如何根据求得的一组解(x0,y0)求出解系,进而求出一组特解。
先用带入扩展欧几里得得出ax+b*y=gcd(a,b)的一个解x0,y0;
再观察两个式子:
ax+b*y=c 0)
a*x0+b*y0=d 1) ( 令d=gcd(a,b) )
将0)式两边都除以d,得:
x*(a/d)+y*(b/d)=c/d
将1)式两边都乘以b/d与0)式比较:
(x0*c/d)*a + (y0*c/d)*b=c
a*x+b*y=c 0)
得x=x0*c/d,y=y0*c/d;
再将上面的结论完善一下:设a,b,c为任意整数,d=gcd(a,b),方程d=ax+by的一组解是(x0,y0),当c是d的倍数,则线性方程组ax+by=c的一组解是(x0*c/d,y0*c/d),当c不是d的倍数时无整数解。
接下来将一个解扩展成一个解系:
1)除以d得: x0*(a/d)+y0*(b/d)=1
因为(a/d)和(b/d)互质,将方程写成:
(x0+u*(b/d))*(a/d)+(y0+v*(a/d))*(b/d)=1即只需u*(b/d)*(a/d) + v*(a/d)*(b/d)=0即可;
所以x,y的解系可以写成 x=(x0+u*(b/d))*(a/d)
y=(y0+v*(a/d))*(b/d)
接下来就可以求满足方程的x的最小正整数了
所以xmin=(x0*(c/d)) mod (b/d)
具体例子是POJ的1061 青蛙的约会