扩展欧几里德算法(递归及非递归实现c++版)
今天终于弄懂了扩展欧几里德算法,有了自己的理解,觉得很神奇,就想着写一篇博客。
在介绍扩展欧几里德算法之前,我们先来回顾一下欧几里德算法。
欧几里德算法(辗转相除法):
辗转相除法求最大公约数,高中就学了,但当时知其然不知其所以然,直到大学才真正理解它的精髓。
理解辗转相除,关键在于理解 gcd(a,b)==gcd(b,a%b)
那么怎么去理解呢?下面是我的理解:
首先对于非负整数a,b,一定可以写成 a=k*b+r(r<b) 的形式
令 g=gcd(a,b) ,则有 g|a ,即 g|(k*b+r)
又 g|b ,所以 g|r
当然,只证得 g 同时整除 b 和 r 依然不能得出 g==gcd(b,r),还可能是gcd(b,r)>g 。
于是我们假设存在 g‘>g(故g'不可能是 a,b 的公约数)
使得 g'|b 且 g'|r
则有 g'|(k*b+r) 即 g'|a
→ g' 是 a,b 的公约数,矛盾。
故 gcd(a,b)==gcd(b,r)(其中 r==a%b) 得证。
下面贴出欧几里德算法的递归和非递归代码:
//递归欧几里德算法
int gcd(int a,int b)
{
return b==?a:gcd(b,a%b);
}
//非递归欧几里德算法
int gcd(int a,int b)
{
int t;
while(b){
t=b;
b=a%b;
a=t;
}
return a;
}
值得注意的是:
1、任意正整数和 0 的最大公约数为正整数本身。
2、即使参数 a<b ,经过一次递归或循环之后,a,b 会自动交换,故开头不需要加 if(a<b)swap(a,b); 语句。
扩展欧几里德算法:
扩展欧几里德算法其实就是为了求出 ax+by=gcd(a,b) 的一个整数解 (x0,y0) ,然后就能得出全部整数解为 (x0+k*b,y0-k*a) 。
递归实现
扩展欧几里德算法的递归实现是基于递归求gcd的过程,它会在gcd函数递归完返回的时候逐步解出一个整数解(x,y) 。
让我们来简单模拟一下 gcd(a,b) 递归返回的过程(数学归纳法得出递推公式)
①在gcd递归到最深处(倒是第一层)的时候,即此时 b0==0 ,可得出方程 a0x+b0y=gcd(a,b) (gcd(a,b)==gcd(a0,b0)==gcd(a1,b1)==…==a0)的一组整数解为x0=1,y0=0。
②假设返回到倒数第 k 层时方程 akx+bky=gcd(a,b) 的一组整数解为 xk , yk
又设返回到倒数第 k+1 层时方程 ak+1x+bk+1y=gcd(a,b) 的一组整数解为 xk+1 , yk+1
则有 akxk+bkyk=ak+1xk+1+bk+1yk+1 其中 ak==bk+1 , bk=ak+1%bk+1
不妨令 xk+1=yk yk+1=xk-ak+1/bk+1*yk
下面贴出递归代码:
//递归扩展欧几里得算法
int exgcd(int a,int b,int&x,int&y)
{
if(b==){
x=,y=;
return a;
}
int r=exgcd(b,a%b,y,x);
y-=a/b*x;
return r;
}
非递归实现
个人感觉扩展欧几里德算法的非递归方式理解起来更为简单。
我们就从一个具体的例子入手吧。
若 a=30 , b=47 , 则 gcd(a , b)=1,那么就是要求解一次不定方程 30x+47y=1 的整数解。
由已知,我们有
观察上述矩阵,第三列的元素变换过程恰好是辗转相除法求最大公约数的过程。
他们的每一步的变换形式(行变换)可用如下通式表示:
当第 2 行 3 列的元素为 0 时,第 1 行 3 列的元素即为 gcd(a , b)。
故最终能得出一组整数解 (x , y)=(11 , -7) 满足 30x+47y=1 。
于是我们可以在非递归欧几里德算法的基础上写出非递归的扩展欧几里德算法,代码如下:
//非递归扩展欧几里得算法
int exgcd(int a,int b,int&x,int&y)
{
int m=,n=,t;
x=,y=;
while(b){
t=m,m=x-a/b*m,x=t;
t=n,n=y-a/b*n,y=t;
t=b,b=a%b,a=t;
}
return a;
}
写到这里算是终于写完了。
这是我写的第一篇博客,本来旨在用最简洁的语言描述最核心的思想,但貌似……可能……大概……与预期有点不符...
我希望通过写博客记录一下自己的想法,即使日后忘记也能一看便知。当然,如果能帮助别人深入理解,那就再好不过了。
最后,如果各位发现文中的错误、有什么建议或者有一些自己的想法,都欢迎在评论区提出。
扩展欧几里德算法(递归及非递归实现c++版)的更多相关文章
- 汉诺塔算法的递归与非递归的C以及C++源代码
汉诺塔(又称河内塔)问题其实是印度的一个古老的传说. 开天辟地的神勃拉玛(和中国的盘古差不多的神吧)在一个庙里留下了三根金刚石的棒,第一根上面套着64个圆的金片,最大的一个在底下,其余一个比一 个小, ...
- 回溯算法 DFS深度优先搜索 (递归与非递归实现)
回溯法是一种选优搜索法(试探法),被称为通用的解题方法,这种方法适用于解一些组合数相当大的问题.通过剪枝(约束+限界)可以大幅减少解决问题的计算量(搜索量). 基本思想 将n元问题P的状态空间E表示成 ...
- C#实现(递归和非递归)高速排序和简单排序等一系列排序算法
本人由于近期工作用到了一些排序算法.就把几个简单的排序算法.想冒泡排序,选择排序,插入排序.奇偶排序和高速排序等整理了出来,代码用C#代码实现,而且通过了測试.希望能给大家提供參考. ...
- 汉诺塔算法c++源代码(递归与非递归)[转]
算法介绍: 其实算法非常简单,当盘子的个数为n时,移动的次数应等于2^n - 1(有兴趣的可以自己证明试试看).后来一位美国学者发现一种出人意料的简单方法,只要轮流进行两步操作就可以了.首先把三根柱 ...
- 欧几里德与扩展欧几里德算法 Extended Euclidean algorithm
欧几里德算法 欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数. 基本算法:设a=qb+r,其中a,b,q,r都是整数,则gcd(a,b)=gcd(b,r),即gcd(a,b)=gcd( ...
- ACM_扩展欧几里德算法
<pre name="code" class="cpp">/* 扩展欧几里德算法 基本算法:对于不完全为 0 的非负整数 a,b,gcd(a,b)表 ...
- C语言实现 二分查找数组中的Key值(递归和非递归)
基本问题:使用二分查找的方式,对数组内的值进行匹配,如果成功,返回其下标,否则返回 -1.请使用递归和非递归两种方法说明. 非递归代码如下: #include <stdio.h> int ...
- poj2115-C Looooops(扩展欧几里德算法)
本题和poj1061青蛙问题同属一类,都运用到扩展欧几里德算法,可以参考poj1061,解题思路步骤基本都一样.一,题意: 对于for(i=A ; i!=B ;i+=C)循环语句,问在k位存储系统中循 ...
- poj1061-青蛙的约会(扩展欧几里德算法)
一,题意: 两个青蛙在赤道上跳跃,走环路.起始位置分别为x,y. 每次跳跃距离分别为m,n.赤道长度为L.两青蛙跳跃方向与次数相同的情况下, 问两青蛙是否有方法跳跃到同一点.输出最少跳跃次数.二,思路 ...
随机推荐
- k8s学习 - API
k8s学习 - API 之前对k8s并没有很深入的了解,最近想把手头一个项目全部放到k8s上,以方便部署,需要研究.这里记录一下自己研究过程中头脑中的理解. k8s 和 docker 首先,需要先理解 ...
- c++简单桶排序
c++简单桶排序 题目一样,还是排序 桶排序是排序算法里比较快的 代码 + 注释 #include <bits/stdc++.h> using namespace std; int mai ...
- Spring Boot2(十一):Mybatis使用总结(自增长、多条件、批量操作、多表查询等等)
一.前言 上次用Mybatis还是2017年做项目的时候,已经很久过去了.中途再没有用过Mybatis.导致现在学习SpringBoot过程中遇到一些Mybatis的问题,以此做出总结(XML极简模式 ...
- 学习 Python 心得
脚本式编程: 通过脚本参数调用解释器开始执行脚本,直到脚本执行完毕.当脚本执行完成后,解释器不再有效. 让我们写一个简单的 Python 脚本程序.所有 Python 文件将以 .py 为扩展名.将以 ...
- 使用R语言预测产品销量
使用R语言预测产品销量 通过不同的广告投入,预测产品的销量.因为响应变量销量是一个连续的值,所以这个问题是一个回归问题.数据集共有200个观测值,每一组观测值对应一种市场情况. 数据特征 TV:对于一 ...
- Linux 文件编程、时间编程基本函数
文件编程 文件描述符 fd --->>>数字(文件的身份证,代表文件身份),通过 fd 可找到正在操作或需要打开的文件. 基本函数操作: 1)打开/创建文件 int open (co ...
- 个人永久性免费-Excel催化剂功能第77波-专业图表制作辅助之批量维护序列点颜色及数据标签
2018年最后一天工作日完成第77波,7是代表完美,2个7,双重的完美,Excel催化剂的2018年从始至终共77波都充满着完美接近极致的功能体验.感谢各位一路相随,陪伴成长.最后一波,再次让数据分析 ...
- 个人永久性免费-Excel催化剂功能第36波-新增序列函数用于生成规律性的循环重复或间隔序列
啃过Excel函数的表哥表姐们,一定对函数的嵌套.数组公式等高级的应用有很深的体会,威力是大,但也烧死不少脑细胞,不少人就在这样的绕函数中光荣地牺牲了,走向从入门到放弃.Excel催化剂的创立,初衷就 ...
- Node.js socket 双向通信
使用场景: 聊天室:大量数据常驻交互: 技术栈: Node.js, Vue.js || 原生JS 服务端代码: const app = require('http').createServe ...
- 《VR入门系列教程》之13---相机与立体渲染
相机.透视图.视口.投影 渲染好的场景都需要一个可以供用户查看的视图,我们通常在3D场景中用相机来提供这种需求.相机相对场景有位置和方向,就像我们生活中的相机一样,它也提供透视图查看方式,这种 ...