扩展欧几里得算法(简单易懂,详细分析)

2023-05-16

扩展欧几里得算法

  • 扩展欧几里得算法证明+应用
    • ==欧几里得算法==
    • ==扩展欧几里得算法==
      • 应用1:求一元二次线性方程的整数解
      • 应用二:求ax=c(mod p)
      • 应用三:求乘法逆元ax=1(mod p)
    • 题目练习
    • 如果你觉得有所收获,能否向你讨一个赞,以此激发博主的开发热情,谢谢!

扩展欧几里得算法证明+应用

扩展欧几里得算法顾名思义是由欧几里得算法延伸出来的一个知识点,在搞懂扩展欧几里得算法之前不妨先来熟悉一下什么是欧几里得算法(又名辗转相除法)

欧几里得算法

1.应用:主要用于求解两个数a和b的最大公约数,我们不妨设(a>b),其公式为gcd(a,b)=gcd(b,a%b)=gcd(a%b,b%(a%b))=…=gcd(x,0),这里的x即为最大公约数.
2.下面展示代码:

/*注意a>b,如果a<b交换一下位置即可*/
int gcd(int a,int b)
{
	/*递归迭代法*/ 
	if(b==0) return a;
	else return gcd(b,a%b); 
}
int gcd(int a,int b)
{
	/*非递归迭代法*/ 
	while(b!=0)
	{
		int r=a%b;
		a=b;
		b=r;
	}
	return a;
}

扩展欧几里得算法

由贝祖定理得任意两个整数a,b,最大公约数为d=gcd(a,b),那么对于任意的整数x,y,ax+by=m,构成的m一定是d的整数倍(即m%d=0)

应用1:求一元二次线性方程的整数解

根据贝祖定理我们可以求得ax+by=c直线上的所有整数解(当然解的个数是无限的),往往题中会让你求其中的一个特殊性质的解(例如:求x为最小的非负整数对应的解(x,y))

思路:我们不妨先求出ax+by=gcd(a,b)的解,然后把解乘以c/gcd(a,b)就得到了原方程ax+by=c的解,细心的同学已经发现c/gcd(a,b)可能不是整数这时候说明原方程没有整数解(即x和y不全为整数)(不满足贝祖定理)

步骤一:求ax+by=gcd(a,b)的特解
我们知道对于任意整数a,b都有ax+by=gcd(a,b)成立,所以得到
1.ax0+by0=gcd(a,b)
2.递归迭代一次得到 bx1+(a%b)y1=gcd(b,a%b)
3.gcd(a,b)=gcd(b,a%b)
由1,2,3式子得ax0+by0=bx1+(a%b)y1

(a%b)y1=(a-a/b*b)*y1

故ax0+by0=bx1+(a-a/b*b)y1

解得x0=y1,y0=x1-(a/b)*y1

不难发现,要得到x0,y0就要先求出下一次迭代的解x1,y1,要得到x1,y1就要再迭代一次求出x2,y2…一直迭代到最后

所以递归迭代到最后ax+by=gcd(a,0)=a, a×1+ b×0=a,所以此时子解为x=1,y=0.然后不断回溯上去就得到了正解x0,y0
代码如下:

int exgcd(int a,int b,int &d,int &x,int &y)//d是a和b的最大公约数x,y是初始解 
{
	/*切记a>b,这是欧几里得算法的特征*/
	if(b==0)
	{
		x=1;
		y=0;
		d=a;
	}
	else
	{	
		exgcd(b,a%b,d,x,y);
		/* x1=y2,y1=x2-(a/b)*y1 扩展欧几里得递归+回溯求初解的公式*/
		int t=y;
		y=x-(a/b)*y;
		x=t;
	}
	return 0;
} 

步骤二:根据特解求通解
已知特解x0,y0
1.ax0+by0=gcd(a,b)
2.ax’+by’=gcd(a,b)

不难得出

x’=x0+b/gcd(a,b)*k (k为任意整数)

y’=y0-a/(gcd(a,b)*k

有人会问为什么不可以直接x’=x0+bk,y’=y0-ak?
因为答案会有遗漏,b和b/gcd(a,b)都是整数,然而b/gcd(a,b)<=b,说到这应该知道为什么答案会遗漏了吧

最小的非负整数解x’是多少呢?
其实就是( x0%( b/gcd(a,b) ) )+b/gcd(a,b) )% ( b/gcd(a,b))
有人会问为什么不直接写成x0%( b/gcd(a,b) ),因为x0可能是负数

步骤3:求出原方程的解
上面已经求出了ax0+by0=gcd(a,b)的特解(x0,y0),所以我们只需要把他等比例放大c/gcd(a,b)倍即可,所有解亦是如此

原方程的通解为
切记不能直接把x’,y’同比例放大不然会漏解,错误答案如下所示
X=x0c/gcd(a,b)+k(b*c)/(gcd(a,b)*gcd(a,b))

Y=y0c/gcd(a,b)-k(a*c)/(gcd(a,b)*gcd(a,b))
正确解如下

X=x0c/gcd(a,b)+kb/(gcd(a,b)

Y=y0c/gcd(a,b)-ka/gcd(a,b)

应用二:求ax=c(mod p)

与前面类似,ax=c(mod p)等同于ax%p=c%p,所以直接转化为一元二次方程问题求ax+py=c的解

应用三:求乘法逆元ax=1(mod p)

解法类似,也是转化为一元二次方程ax+py=1的解

我们一般把x的最小非负整数解作为a的乘法逆元

题目练习

青蛙约会
题目描述
两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。

我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了一条首尾相接的数轴。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬度线总长L米。现在要你求出它们跳了几次以后才会碰面。

输入格式
输入只包括一行5个整数x,y,m,n,L

其中0<x≠y < =2000000000,0 < m、n < =2000000000,0 < L < =2100000000。

输出格式
输出碰面所需要的天数,如果永远不可能碰面则输出一行"Impossible"。

输入
1 2 3 4 5
输出
4

题解
由题意我们可以列出方程
x+my=y+nt(%L)
设未知数t,q分别表示青蛙A和青蛙B跳的次数
那么可以得到
(m-n)t+Lq=y-x(modL)
设m-n=A,y-x=B,代入得到At+Lq=B(modL)
因为我们已知ax+by=gcd(a,b)这样的一个公式
所以我们先求At+Lq=gcd(A,L),用扩展欧几里得可以得到一个特解x0;
因为gcd(A,L)要求A,L都要大于0,如果A<0,等式两边同乘以一个负号即可,也即A=-A,B=-B,如果B<0,B+=L;
最后我们把x0*B/gcd(A,L),就得到了原方程的解
但是题目要求最小的正整数x0,我们设s=L/gcd(A,L),x0=(x0%s+s)%s就是答案

代码:

/*扩展欧几里板子*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll exgcd(ll &x,ll &y,ll &g,ll a,ll b)//g为gcd(a,b) 
{
	if(b==0)
	{
		x=1;
		y=0;
		g=a;
		return 0;
	} 
	exgcd(x,y,g,b,a%b);
	ll x1=y;
	ll y1=x-(a/b)*y;
	x=x1;
	y=y1;
	return 0;
}
int main()
{
      ll m,n,L;
      ll t,q,g;
      ll x,y;
      cin>>x>>y>>m>>n>>L;
      ll a=m-n;
      ll c=y-x;
      ll b=L;
      if(a<0)
      {
      	a=-a;
      	c=-c;
      	if(c<0) c+=L;
	  }
      exgcd(t,q,g,a,b);
      if(c%g!=0||m==n)
      {
      	printf("Impossible\n");
      	return 0;
	  }
      ll s=L/g; 
	  t=t*c/g;
      ll ans=(t%s+s)%s;
      cout<<ans;
      return 0;
} 

接下来我们趁热打铁,试着谢谢这道题
五指山
西游记中孙吾空大闹天宫,如来佛祖前来降伏他,说道:“我与你打个赌赛;你若有本事,一筋斗打出我这右手掌中,算你赢,再不用动刀兵苦争战,就请玉帝到西方居住,把天宫让你;若不能打出手掌,你还下界为妖,再修几劫,却来争吵。”
那大圣闻言,暗笑道:“这如来十分好呆!我老孙一筋斗去十万八千里。他那手掌,方圆不满一尺,如何跳不出去?”急发声道:“既如此说,你可做得主张?”佛祖道:“做得!做得!”伸开右手,却似个荷叶大小。那大圣收了如意棒,抖擞神威,将身一纵,站在佛祖手心里,却道声:“我出去也!”你看他一路云光,无影无形去了。大圣行时,忽见有五根肉红柱子,撑着一股青气。他道:“此间乃尽头路了。这番回去,如来作证,灵霄殿定是我坐也。”翻转筋斗云,径回本处,站在如来掌:“我已去,今来了。你教玉帝让天宫与我。”
如来骂道:“你正好不曾离了我掌哩!”大圣道:“你是不知。我去到天尽头,见五根肉红柱,撑着一股青气,我留个记在那里,你敢和我同去看么?”如来道:“不消去,你只自低头看看。”那大圣睁圆火眼金睛,低头看时,原来佛祖右手中指写着“齐天大圣,到此一游。”大圣大吃了一惊道:“有这等事!有这等事!我将此字写在撑天柱子上,如何却在他手指上?莫非有个未卜先知的法术?我决不信!不信!等我再去来!”
好大圣,急纵身又要跳出,被佛祖翻掌一扑,把这猴王推出西天门外,将五指化作金、木、水、火、土五座联山,唤名“五行山”,轻轻的把他压住。
我们假设佛祖的手掌是一个圆圈(所以任凭大圣一个筋斗云十万八千里也是飞不出其手掌心),圆圈的长为n,逆时针记为:0,1,2,…,n-1,而大圣每次飞的距离为d.现在大圣所在的位置记为x,而大圣想去的地方在y。现在要你告诉大圣至少要多少筋斗云才能到达目的地。
Input
有多组测试数据。
第一行是一个正整数T,表示测试数据的组数。
每组测试数据包括一行,四个非负整数,n(2 < n < 10^9),表示如来手掌圆圈的长度;d(0 < d < n),筋斗所能飞的距离;x(0 <= x < n),大圣的初始位置;y(0 <= y < n),大圣想去的地方。
注意孙悟空的筋斗云只沿着逆时针方向翻。

Output
对于每组测试数据,输出一行,给出大圣最少要翻多少个筋斗云才能到达目的地。如果无论翻多少个筋斗云也不能到达,输出“Impossible”.

Sample Input
2
3 2 0 2
3 2 0 1

Sample Output
1
2

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void exgcd(ll a,ll b,ll &g,ll &x,ll &y)
{
	if(b==0)
	{
		g=a;
		x=1;
		y=0;
		return ;
	}
	else
	{
		ll x1,y1;
		exgcd(b,a%b,g,x,y);
		x1=y;
		y1=x-(a/b)*y;
		x=x1;
		y=y1;
	}
	return ;
}
int main()
{
	int t ;
	cin>>t;
	while(t--)
	{
		ll n,d,x,y,g;
		ll t,p;
		cin>>n>>d>>x>>y;
		ll c=y-x;
		
		if(d<0)
		{
			d=-d;
			c=-c;
			if(c<0) c+=n; 
		}
		exgcd(d,n,g,t,p);
		if(c%g!=0)
		{
			printf("Impossible\n");
		}
		else
		{
			t=t*c/g;
			ll s=n/g;
			t=(t%s+s)%s;
			printf("%lld\n",t);
		}
	}
	return 0;
}

如果你觉得有所收获,能否向你讨一个赞,以此激发博主的开发热情,谢谢!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

扩展欧几里得算法(简单易懂,详细分析) 的相关文章

  • 求字符串的最长回文

    主要锻炼的就是动态规划的思想 xff01 xff01 xff01 掌握这种思想 xff0c 工作中不一定用得上 xff0c 但是多一种思想就多一种可能 span class token comment dp i j 表示s的子串 xff08
  • C++查找指定目录下的特定后缀文件并按照创建时间排序

    在一个项目中 xff0c 遇到了这个需求 于是windows 43 vs平台上实现了这个功能Demo 测试完毕后移植到了具体的项目中 span class token macro property span class token dire
  • Ubuntu下Qt程序生成Core文件便于调试

    需要在运行时生成core dump文件 xff0c 以排查出错的代码行 首先在pro结尾里加入 xff1a QMAKE CC 43 61 g QMAKE CXX 43 61 g QMAKE LINK 43 61 g 在终端输入 ulimit
  • linux查看进程所有子进程和线程

    线程是现代操作系统上进行并行执行的一个流行的编程方面的抽象概念 当一个程序内有多个线程被叉分出用以执行多个流时 xff0c 这些线程就会在它们之间共享特定的资源 xff08 如 xff0c 内存地址空间 打开的文件 xff09 xff0c
  • 一款二进制文件查看器

    由于使用的是Notepad 43 43 64位版本 xff0c 在网上找了很多二进制查看插件HexEditor dll要么是32位不兼容 xff0c 要么是出现除零的错误 xff08 以前找到过一次支持Notepad 43 43 64位版本
  • YOLO目标检测

    一 背景 基于深度学习技术的视觉目标检测近年去的长足发展 但仍然有许多方面问题需要优化 二 YOLO算法的特点 YOLO作为一种性能优异的通用目标检测系统 xff0c 为了保证检测的效率 xff0c 提出one stage的思想 xff0c
  • (Qt中添加编译选项)QT在交叉编译时出现parameter passing for argument of type ‘std::_Rb_tree xxxxx changed in GCC 7.1

    QT版本都是5 1x 先是在Ubuntu机器上写的代码 xff0c GCC版本为5 4 xff0c 代码编译无 任何警告 后来移植到开发板 xff08 GCC版本为7 1 xff09 进行编译时 xff0c 提示这种警告 发生在代码中对st
  • C++按行读取文本并解析

    项目中需要按行读取文本文件 xff0c 并对每一行内容进行解析 每一行都是固定的字段数 xff0c 字段之间用空格隔开 span class token macro property span class token directive k
  • error C2447: “{”: 缺少函数标题(是否是老式的形式表?)

    error C2447 缺少函数标题 是否是老式的形式表 网上有人说 这个BUG是因为在win7上使用了 LF 的格式编码导致的 使用Notepad 43 43 修改成 BOM UTF8 和 windows 的 CR LF 格式一切正常 确
  • Visual Studio 2017 代码自动对齐

    点 编辑 高级 设置选定内容的格式 或者按Ctrl 43 K 然后再按Ctrl 43 F 就好了 你可以在常用快捷键自定义 窗口中进行查看 1 进入工具 选项 对话框 2 选择 环境 键盘 3 在 显示命令包含 下面的对话框中输入 对齐 关
  • CSDN 排版之颜色、字体、字号及背景色

    颜色 xff1a span class token operator lt span font color span class token operator 61 span blue span class token operator g
  • 使用QTCreator编程时,如何利用dmp文件定位程序奔溃

    写这篇文章之前 xff0c 看了一些其他人的博客 xff0c 但不是很详细 xff0c 缺这少那的 xff0c 好多都是复制粘贴别人的东西 自己动手弄了弄 xff0c 可以使用 xff0c 就记下来备忘与分享 前言 开发环境说明 编程IDE
  • Pytorch中transforms.RandomResizedCrop使用说明

    加载数据 训练集数据扩充 数据增强 和归一化 数据扩充 数据增强 的意义在于通过人为的随机范围裁剪 缩放 旋转等操作 增大训练集中的数据多样性 全面性 进而提高模型的泛化能力 训练集数据扩充和归一化 在验证集上仅需要归一化 data tra
  • C++中调用Python的办法

    1 背景 一直采用C 43 43 作为主语言开发 xff0c 最近遇到一个项目需要解析PDF文件中的文本内容 xff0c 直接采用C 43 43 来做显得不是很方便 xff0c 但用python来做就显得很简单了 难点在于如何C 43 43
  • Qt Creator远程调试嵌入式ARM开发板

    1 环境 Win10 64位系统上通过Virtual Box安装了一个Ubuntu虚拟机 ubuntu的版本 xff1a Linux kernel 4 15 0 142 generic 146 16 04 1 Ubuntu SMP Ubun
  • 套接字(描述符)读取指定的字节数

    检测fd句柄是否可读 xff0c ms毫秒超时 参数 xff1a df in 检测的句柄 ms in 超时 xff0c 毫秒 返回 xff1a 1 可读 xff0c 或者已经断开 0 超时 xff0c 仍然不可读 1 错误 int IsRe
  • 4.4线索二叉树遍历

    1 中序线索二叉树遍历 找到第一个中序遍历的结点 ThreadNode span class token operator span span class token function Firstnode span span class t
  • 自动根据本机字节序 将小端字节序的报文(字符数组)转为整数

    1 xff0c 判断本机的字节序 xff08 大端优先 小端优先 xff09 判断当前PC为大端还是小端字节序 64 返回值 xff1a 1 大端 xff1b 0 小端 int JudgeEndianOfPC int num 61 1 if
  • 智能指针的使用

    智能指针在C 43 43 11版本之后提供 xff0c 包含在头文件 lt memory gt 中 xff0c shared ptr unique ptr weak ptr 1 xff0c shared ptr的使用 shared ptr使
  • 图像检索系列——利用深度学习实现以图搜图

    转载自 xff1a 图像检索系列 利用深度学习实现以图搜图 知乎 前言 在上一篇文章 图像检索系列 利用 Python 检测图像相似度 中 xff0c 我们介绍了一个在图像检索领域非常常用的算法 感知哈希算法 这是一个很简单且快速的算法 x

随机推荐

  • Windows下select模型(以及EAGAIN、EWOULDBLOCK、EINTR)

    在这里记录一下 xff0c 以前都是新项目用到了就从旧项目中拷贝 自从将博客当作记事本 xff0c 发现自己多了一个好习惯 Windows下select模型 程序员攻略 CSDN博客 套接字IO超时设置和使用select实现超时管理 wj
  • RANSAC算法理解

    RANSAC是 RANdom SAmple Consensus xff08 随机抽样一致 xff09 的缩写 它可以从一组包含 局外点 的观测数据集中 xff0c 通过迭代方式估计数学模型的参数 它是一种不确定的算法 它有一定的概率得出一个
  • C++ 环形缓冲区(队列)简单实现

    1 说明 在实际工作中 xff0c 如果数据流量过大 xff0c 可以先把数据接收到数据缓冲区中 xff0c 处理之后再取出 我们定义的包协议可以采用定长包 xff0c 可以采用不定长度的包 xff0c 环形缓冲区都能处理 2 使用场景 2
  • Visual Studio Code (vscode) 配置 C / C++ 环境

    Visual Studio Code vscode 配置 C C 43 43 环境 步平凡 博客园 在电脑安装软件管控严格的情况下 xff0c 想装VS装不了 xff0c 就装轻量版的VSCode了 以上写得很好 xff0c 照做即可 本人
  • c++实现basename

    window API居然不包含Linux中很好用的basename函数 xff0c 实现了一下 xff0c 留个记录 xff0c 省得日后重复写 std string m basename std string fullPath size
  • tortoiseGit教程

    0 前言 TortoiseGit其实是一款开源的git的版本控制系统 xff0c 也叫海龟git TortoiseGit提供了人性化的图形化界面 xff0c 不用像Git一样输入许多语句 xff0c 像git init git add gi
  • 用STL库创建线程

    测试了3种方式 xff1a 1 xff1a 子线程不带返回值 2 xff1a 子线程带返回值 3 xff1a 子线程带引用类型参数 使用join方式 xff0c 让父线程等待子线程运行结束 TestTemp cpp 定义控制台应用程序的入口
  • 4.5树的存储

    双亲表示法 xff0c 孩子表示法 xff0c 孩子兄弟表示法 1 双亲表示法 查找双亲简单 空数据导致遍历更慢 xff0c 查指定节点的孩子只能遍历 span class token keyword typedef span ElemTy
  • Windows下MySQL数据库的安装、配置及C++使用案例

    1 安装及配置 Windows判断本地是否安装mysql以及mysql安装过程 企鹅要去银河思考人生 xff01 xff01 xff01 的博客 CSDN博客 windows查看是否安装mysql 注意按照文中提示 xff0c 配置好环境变
  • C++获取系统毫秒级时间(自1970年1月1日至今的毫秒数)

    跟系统时间相关的 ifdef WIN32 include lt time h gt include lt windows h gt else include lt sys time h gt endif unsigned long long
  • Window 10下SQL Server的安装配置以及C++使用案例

    1 SQL Server2008的安装与配置 参照下面这篇博客实现即可 里面提供了安装包下载方式 xff08 百度网盘有点慢 xff09 安装及配置步骤 SQLServer安装教程 xff08 史上最详细版本 xff09 杨林伟的博客 CS
  • 基于OpenCV实现的多角度、多目标模板匹配项目实战案例

    1 说明 本案例采用NCC的匹配 金字塔 为了加速 思想 基于OpenCV实现的多角度 多目标模板匹配 不支持尺度不变 若研究旋转 尺度不变性的匹配 请参考本人的OpenCV专栏内的 nbsp OpenCV实现多角度多尺度模板匹配 基于形状
  • 程序日志模块的两种模式

    程序员都知道程序的运行日志在不少时候都非常有用 xff0c 利于排查 理清逻辑 一般而言 xff0c 日志都按天生成 xff0c 并且具备自动清理多少天以前的旧日志 xff0c 避免无限增长占用磁盘 下图展示了2种日志模式 模式一 1 xf
  • C++开发面试常考

    C 43 43 后台开发面试常考 pudn com
  • 如何在微软官网上下载旧版本的visual studio

    想在微软官网下载旧版本的VS 太长不想看的可以直接戳网址进入最终的界面 xff1a Visual Studio 较旧的下载 2019 2017 2015 和以前的版本想从官网首页一步一步进入到最终下载界面的可以看下面详细步骤 xff1a 1
  • 基于OpenCV实现的RANSAC随机抽样一致性直线拟合

    概要 本文介绍基于ransac随机抽样一致性随机抽样一致性的直线拟合方法 涵盖一下的内容 ransac的算法思想 ransac的算法步骤 如何调整ransac算法迭代的次数 基于opencv编码实现 ransac算法流程 RANSACRAN
  • 基于OpenCV(C++)实现的RANSAC随机抽样一致性的曲线拟合(二次)

    nbsp 0 前言 nbsp nbsp 前不久整理了RANSAC直线拟合的文章 基于OpenCV实现的RANSAC随机抽样一致性直线拟合 thequitesunshine007的博客 CSDN博客 这篇文章与其类似 只是从拟合直线变为拟合曲
  • 最小二乘least-squares拟合曲线(三次或多次)

    1 说明 基于最小least squares去拟合出多次曲线 考虑到了所有的样本点 因此这种方法对噪声敏感 尤其是遇到较为突兀明显的噪声时 曲线的形状易受干扰 2 代码 代码细节仔细读基本都能读懂 或者查一下也不是什么大问题 include
  • 4.6树和森林的遍历

    一 树的遍历 1 先根遍历 对应二叉树先序遍历 span class token keyword void span span class token function PreOrder span span class token punc
  • 扩展欧几里得算法(简单易懂,详细分析)

    扩展欧几里得算法 扩展欧几里得算法证明 43 应用 61 61 欧几里得算法 61 61 61 61 扩展欧几里得算法 61 61 应用1 xff1a 求一元二次线性方程的整数解应用二 xff1a 求ax 61 c mod p 应用三 xf