如何使用拓展欧几里得算法求解模线性方程组(详解)

Posted wenzhixin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用拓展欧几里得算法求解模线性方程组(详解)相关的知识,希望对你有一定的参考价值。

  式子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即可;
所以xy的解系可以写成 x=(x0+u*(b/d))*(a/d)

y=(y0+v*(a/d))*(b/d)

接下来就可以满足方程的x的最小整数

所以xmin=(x0*(c/d)) mod (b/d)

具体例子是POJ的1061 青蛙的约会

https://www.cnblogs.com/wenzhixin/p/9343420.html



























以上是关于如何使用拓展欧几里得算法求解模线性方程组(详解)的主要内容,如果未能解决你的问题,请参考以下文章

求解模线性方程

扩展欧几里德算法的应用

《夜深人静写算法》数论篇 - (11) 线性同余

《夜深人静写算法》数论篇 - (11) 线性同余

Python版本的常见模板 数论

数论之拓展欧几里得求解不定方程和同余方程组