欧几里德|扩展欧几里德

1、欧几里德 – 求解最大公约数

gcd(a,b) = gcd(bn+r, b) = gcd(a%b, b) = gcd(b, a%b) 假定 a>b; a=bn+r;

int gcd(int a, int b){
     return b ? gcd(b, a%b) : a;
}

int gcd(int a , int b)
{
     int r;
     while(b!=0)
     {
          r = a; a = b; b = r%b;
     }
     return a;
}

即使a<b 上面代码也没问题,经过第一次调用a, b会对调的

2\ 扩展欧几里德 – 求解方程 ax+by = gcd(a, b);
基本算法:对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在整数对 x,y ,使得 gcd(a,b)=ax+by。

扩展欧几里德算法的应用主要有以下三方面:
(1)求解不定方程;
(2)求解模线性方程(线性同余方程);
(3)求解模的逆元;

假定 a>b
gcd(a, b) = a*x + b*y;
gcd(b, a%b ) = b*x1 + (a%b ) *y1 = b*x1 + (a- a/b *b )*y1;
gcd(a, b ) = gcd(b, a%b);

求解
b==0
gcd(a,b) = a = a*x + b*y; ==> x=1; y=0;
b!=0
a*x + b*y = b*x1 + (a-a/b * b) * y1 = a*y1 + b *(X-a/b*y1);
==> x = y1 = … ;
==> y = x1-a/b*y1 = …;
通过不断迭代就能求解x, y

// 扩展的欧几里德-递归算法
int exgcd(int a, int b, int *x, int *y)
{
     if ( b == 0)
     {
          *x=1;
          *y=0;
          return a;
     }
     // 先求出内部x, y
     int r = exgcd(b, a%b, y, x);
     // 更新外部x , y
     *y -= a/b * (*x);
}

1、递推公式
根据下图 a=1398 b=324 商q=a/b 余数r=a%b
这里写图片描述

gcd(a, b) = gcd(b, r1=a%b) = gcd(r1, r2=b%r1) = gcd(r2, r3=r1%r2)
每一个 r 都可以转换用a, b 标示
假定 r1 = a*x1+b*y1; r2=a*x2+b*y2;
r3 = a*x3 + b*y3 = r1 % r2 = (a * x1 + b y1) - r1/r2 ( a*x2 + b *y2)
= a(x1- r1/r2 * x2) + b(x2 - r1/r2 * y2);

==> r3 = r1 % r2;
==> x3 = x1- r1/r2 * x2
==> y3 = x2 - r1/r2 * y2

也就是说 有了x1 y1 r1 x2 y2 r2 就能推动上面的等式
当 r3 = r1 % r2 = 0时 结束, 此时 r2 = gcd(a, b) = gcd(r2, 0) = a*x2+b*y2; 此时 x2, y2, r2 即为所求

2、初始值
令x1=1 , y1=0; r1=a*1 + b*0 = a =;
令x2=0, y2=1; r2=a*0 + b*1 = b = b%a ; (b<\a ==> b=b%a)

x1\x2\y1\y2不能随便取值 要满足
因为 gcd(a, b) = gcd(b, r1=a%b) = gcd(r1, r2=b%r1)
所以要满足 (a*x2+b*y2) = b % (a*x1+b*y1)
令x2=0; y2=1; 那么只要满足 a*x1 + b*y1 > b 都可以 eg x1=1;x2=1;r1=a+b; …

// 扩展的欧几里德-非递归算法
 int exgcd(a, b)
 {
     int x1, y1, r1, x2, y2, r2, x3, y3, r3;
     x1=1; y1=0; r1=a;
     x2=0; y2=1; r2=b;
     while( r1%r2 )
     {
         r3 = r1%r2;
         x3 = x1 - r1/r2 * x2;
         y3 = y1 - r1/r2 * y2;

         //  交换
         x1=x2;y1=y2;r1=r2;
         x2=x3;y2=y3;r2=r3;
     }   
     printf("%d=%d*%d+%d*%d\n",r2, a, x2, b, y2);
     return 0;
 }

有关链接
http://anh.cs.luc.edu/331/notes/xgcd.pdf
http://math.cmu.edu/~bkell/21110-2010s/extended-euclidean.html
http://blog.csdn.net/yoer77/article/details/69568676

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值