拓展欧几里得算法

学习拓展欧几里得算法的目的是为了解决直线上的点的问题:求直线ax + by +c = 0 上有多少个整点(x, y)满足x∈[x1, x2], y∈[y1, y2];(在此为了推导方便,把ax +by + c = 0换成 ax +by = c, 效果相同)

在下面我会用@1解决@2,再用@2解决@3,最后回来解决@1, 这样就解决了@3(直线上的点的问题)

 

拓展欧几里得算法: ax + by = gcd ( gcd 表示gcd(a, b), 下同)         @1

假设c/gcd为整数, 上式两边*(c/gcd)      得ax(c/gcd) + by(c/gcd) = c           @2   (若c/gcd不为整数解,则直线上的点的问题也不会有整数解)

由上式解可得ax + by = c 的一组解 ,即可得直线上的点的问题的一组解。 由这组解(x。, y。)去求全部解:(x。+s。,y。- t。);                 @3

a(x。+s。) + b(y。- t。) = c ,结合ax。+by。= c可得:as。= bt。两边 / gcd ,得:a / gcd *s。= b / gcd * t。由于a/gcd与b/gcd互质,则s。必为b/gcd的倍数,

设为s。= k*b/gcd , 可推出t。= k*a/gcd

则ax + by =c 的解为x = x。+k*b/gcd, y = y。- k *a/ gcd;    k 为任意整数

x 的最小非负数解为((x。%  (b/gcd) ) + b/gcd)%(b/gcd)   写的这么麻烦是防止x。为负数时出错

注意(x。, y。)是ax+by = c的一组解,直线上点的坐标要用拓展欧几里得里的解表示则为:x = x 1c/gcd+ kb/gcd; y = y 1c/gcd - ka/gcd (x1, y1)为拓展欧几里得里的一组解

 

回来解决@1:

我们先解决这个问题:    若ax 1+ by1=gcd, bx2 + (a%b)y2 = gcd ,如何通过(x2, y2)求得(x1, y1)的一组解

首先 :a%b = a- a/b*b    (计算机的思维就是这么妙) 

联立上式得:ax1+by1=ay2 + b(x2-(a/b)y2) ,可以得到它的一组解(注意就是一组解) x1 = y2;  y1 =x2 - (a/b)y2            @4

解决这个问题后,我们就来解决ax+by =gcd的问题

首先gcd(a, b)  = gcd ( b, a%b) ,边界:b = 0

则把上式不断变换,得到 a * x + 0 * y= gcd(a, 0) = a, 注意:这里的a,x,y都不是原来的a, x, y了, 在这里可取 x =1 , y =0 ; a = gcd (a, 0) = gcd(gcd为原来的a,b 的最大公因数),可得a值 

然后通过@4的式子不断回溯,可得最初的ax + by = gcd 的一组解

最后和@3中差不多 ,设全部解:(x1+s。,y1 - t。),然后代入,解得x = x1+k*b/gcd, y = y1- k *a/ gcd; 

x 的最小非负数解为((x1%  (b/gcd) ) + b/gcd)%(b/gcd)  

拓展欧几里得算法:

 1 int exGcd(int a, int b, int &x, int &y)
 2 {
 3     if(b == 0)
 4     {
 5         x = 1;
 6         y = 0;
 7         return a;
 8     }
 9     int g = exGcd(b, a % b, x, y);      //g 是 gcd 
10     int temp = x;
11     x = y;
12     y = temp - a / b * y;
13     return g;
14 }

嗯,基本就是这些了

 

补充:

1.思考了a, b为负数的情况,当a,b 为负数时代码应该要有调整,使得传入exGcd的a, b为正数,并对对应的x或y进行取反操作;

posted @ 2019-05-06 10:21  the_sky314  阅读(278)  评论(0编辑  收藏  举报