欧几里得算法 贝祖(裴蜀)等式

news2024/10/9 21:23:48

一、欧几里得算法:

欧几里得算法(又称辗转相除法)是一种求解两个整数最大公约数(Greatest Common Divisor, GCD)的经典算法。它的基本思想如下:

两个整数的最大公约数等于其中较小的那个数与两数相除所得的余数的最大公约数

可以通过递归来实现:

//求最大公约数——欧几里得算法,即辗转相除法
//gcd(a,b) <=> gcd(b,a%b)
int gcd(int a, int b) {
	if (b == 0) return a; //边界
	return gcd(b, a % b); //假设已经求出了a%b的最大公约数
}

欧几里得算法的应用:——求整数点:

已知a(x1,y1), b(x2,y2)都是整数点, c(x3,y3)在a,b连线上并满足c点也是整数点,求c点的可能坐标:

//求整数点:已知a(x1,y1), b(x2,y2)都是整数点, c(x3,y3)在a,b连线上并满足c点是整数点,求c点的坐标
vector<pair<int,int>> GetC(int x1, int y1, int x2, int y2) {
	int x = abs(x2 - x1);
	int y = abs(y2 - y1);
	int gcd_xy = gcd(x, y);//求曼哈顿距离差最大公约数

	vector<pair<int,int>> res;//存放结果

	int dx = x / gcd_xy;//x方向的步长
	int dy = y / gcd_xy;//y方向的步长

	int cnt = 1;

	int dir_x = ((x1 - x2) < 0) ? 1 : -1;//判断从a到b,x方向的方向
	int dir_y = ((y1 - y2) < 0) ? 1 : -1;

	while (cnt<gcd_xy) {
		res.push_back({ x1 + dir_x * cnt * dx,y1 + dir_y * cnt * dy });
		cnt++;
	}
	return res;
}


二、贝祖(裴蜀)等式:

1.定义:

对任何整数 a a a b b b和它们的最大公约数 d d d,关于未知数 x x x y y y的线性方程(称为裴蜀等式):

a x + b y = m ax + by = m ax+by=m

有整数解当且仅当 m m m d d d的倍数。

裴蜀等式有解时必然有无穷多个整数解,每组解 x , y x, y x,y称为裴蜀数,可用扩展欧几里得算法(Extended Euclidean algorithm)获得。

特别地,方程 a x + b y = 1 ax + by = 1 ax+by=1 有整数解当且仅当整数 a a a b b b互素


2.求解裴蜀公式:

扩展欧几里得算法求裴蜀公式的一个解:

a x + b y = d ax+by=d ax+by=d,假设 d = g c d ( a , b ) d=gcd(a,b) d=gcd(a,b)

  • 扩展欧几里得算法就是在求 a , b a,b a,b 的最大公约数 d = gcd ( a , b ) d=\text{gcd}(a,b) d=gcd(a,b) 的同时,可求出贝祖等式 a x + b y = d ax + by = d ax+by=d 的一个解 ( x 0 , y 0 ) (x_0,y_0) (x0,y0)

(1)如何推导?(可以利用相邻两步之间的过程进行推导,提出系数a,b,对照x和y即可得出,不太好打出来,可自行推导或查找资料)

  • x = y 1 x = y_1 x=y1
  • y = x 1 − a b y 1 y = x_1 - \frac{a}{b}y_1 y=x1bay1

下面的ext_gcd函数即是求解扩展的欧几里得算法;
调用LinearEquation函数求解贝祖等式的一个解,并乘以倍数m/d,保证解的正确性。

  • 如果 a x + b y = m ax+by=m ax+by=m,m不是 g c d ( a , b ) gcd(a,b) gcd(a,b)的倍数,则该方程无解:

代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>

using namespace std;

//扩展欧几里得算法:求解ax+by=m的整数解
int x, y;
int ext_gcd(int a, int b) {
	if (b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	int res = ext_gcd(b, a % b); //假设已经求出了b,a%b的整数解
	int temp = x;
	x = y;
	y= temp - a / b * y;
	return res;
}

void LinearEquation(int a, int b, int m) {
	int d = ext_gcd(a, b);
	if (m % d != 0) {
		printf("无解\n");
		return;//无解
	}
	int n = m / d;
	x *= n;
	y *= n;
	cout << "gcd: "<<d<<endl;
}

int main(void)
{
	int a, b, m;
	cin >> a >> b >> m;
	LinearEquation(a, b, m); //ax+by=m的整数解
	cout <<"x: " <<x << " " <<"y: " << y << endl;
	return 0;
}

求裴蜀公式的通解:

(2)通解?

  • x = x 0 + b g c d ∗ t x = x_0 + \frac{b}{gcd}*t x=x0+gcdbt − − > --> >所有的 x 对 b 模
  • y = y 0 − a g c d ∗ t y = y_0 - \frac{a}{gcd}*t y=y0gcdat − − > --> >所有的 y 对 a 模

或者

  • x = x 0 − b g c d ∗ t x = x_0 - \frac{b}{gcd}*t x=x0gcdbt − − > --> >所有的 x 对 b 模
  • y = y 0 + a g c d ∗ t y = y_0 + \frac{a}{gcd}*t y=y0+gcdat − − > --> >所有的 y 对 a 模

即x如果加的话,y就要对应的减,从而保证二者的平衡,反之亦然。

由于贝祖公式一旦有解,则有无穷解,所以这里并未给出具体的求解代码,可根据需求求解相应的解。


(3)如果想得到 x > 0 x > 0 x>0 的第一个解?

  • b / = d b/=d b/=d
  • x = ( x 0 % b + b ) % b x = (x_0 \% b + b) \% b x=(x0%b+b)%b

利用基本的取模运算即可求解,x和y只需求出一个即可得出另一个。


3.裴蜀公式的应用:

让我们来看一看2016年第七届蓝桥杯B组C/C++决赛题——一步之遥

题目如下:

从昏迷中醒来,小明发现自己被关在X星球的废矿车里。
矿车停在平直的废弃的轨道上。
他的面前是两个按钮,分别写着“F”和“B”。

小明突然记起来,这两个按钮可以控制矿车在轨道上前进和后退。
按F,会前进97米。按B会后退127米。
透过昏暗的灯光,小明看到自己前方1米远正好有个监控探头。
他必须设法使得矿车正好停在摄像头的下方,才有机会争取同伴的援助。
或许,通过多次操作F和B可以办到。

矿车上的动力已经不太足,黄色的警示灯在默默闪烁...
每次进行 F 或 B 操作都会消耗一定的能量。
小明飞快地计算,至少要多少次操作,才能把矿车准确地停在前方1米远的地方。

请填写为了达成目标,最少需要操作的次数。

求解方法也很简单,就是解一个贝祖等式:
97 x − 127 y = 1 97x-127y=1 97x127y=1
这里的正负号其实影响不大,看怎么理解了:
可以理解为:

  • 97 97 97 127 127 127 g c d gcd gcd,得 x = 55 , y = − 42 x=55,y=-42 x=55,y=42;即向前 55 ∗ 97 m 55*97m 5597m,再向前 − 42 ∗ 127 -42*127 42127m;
  • 97 97 97 − 127 -127 127 g c d gcd gcd,得 x = 55 , y = 42 x=55,y=42 x=55y=42;即向前 55 ∗ 97 55*97 5597m,再向后 42 ∗ 127 42*127 42127m;

代码如下,和扩展欧几里得算法基本一致:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>

using namespace std;

//扩展欧几里得算法:求解ax+by=m的整数解
int x, y;
int ext_gcd(int a, int b) {
	if (b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	int res = ext_gcd(b, a % b); //假设已经求出了b,a%b的整数解
	int temp = x;
	x = y;
	y= temp - a / b * y;
	return res;
}

bool LinearEquation(int a, int b, int m) {
	int d = ext_gcd(a, b);
	if (m % d != 0) {
		printf("无解\n");
		return false;//无解
	}
	int n = m / d;
	x *= n;
	y *= n;
	cout << "gcd: "<<d<<endl;
	return true;
}

int main(void)
{
	int a, b, m;
	cin >> a >> b >> m;
	if (LinearEquation(a, b, m)) {
		//ax+by=m的整数解
		cout << "x: " << x << " " << "y: " << y << endl;
		cout << "res: " << abs(x) + abs(y) << endl;
	}

	return 0;
}


当然,题目中求的是最少操作次数,上面并没有对其进行判断。但通过上面的(2):通解,可以验证这就是最少的操作次数,因为操作次数是x和y的绝对值的和,在当前情况下,无论是增加x,减少y;还是减少x,增加y,都会增大操作次数。


扩展:

所以,通过扩展欧几里得求得的一组解的绝对值和一定是最小的

证明:
对整个递归过程进行讨论:

(1)递的过程——求出每层的a和b:(设层数c从1->n)
假设我们输入的a,b满足 a > = b a>=b a>=b,若不满足就交换a,b。那么在求gcd的过程中a总是大于b,即 a / b a/b a/b总是大于1。

(2)归的过程——更新每层的x和y:(层数c从n->1)
因为递归求解gcd的最后一步必定是 d x + 0 y = d , d = g c d ( a , b ) dx + 0y = d,d=gcd(a,b) dx+0y=dd=gcd(a,b)
此时 x = 1 , y = 0 x=1,y=0 x=1,y=0

然后利用递推公式求解上一层的x和y。

  • x = y 1 x = y_1 x=y1
  • y = x 1 − a b y 1 y = x_1 - \frac{a}{b}y_1 y=x1bay1

对每层来说 a / b a/b a/b大于1,记为q
注意:

  • 不同层的a,b大小是不一定相同的;
  • q只是一个大于1的记号,也不一定相同;
  • 设c为层数;
  • sa为sum of abs ;

迭代如下:

c = n , x = 1 , y = 0 , s a = 1 c=n,x=1,y=0,sa=1 c=nx=1y=0sa=1
c = n − 1 , x = 0 , y = 1 , s a = 1 c=n-1,x=0,y=1,sa=1 c=n1x=0y=1sa=1
c = n − 2 , x = 1 , y = − q , s a = q + 1 c=n-2,x=1,y=-q,sa=q+1 c=n2x=1y=qsa=q+1
c = n − 3 , x = − q , y = 1 + q ∗ q , s a = q 2 + q + 1 c=n-3,x=-q,y=1+q*q,sa=q^2+q+1 c=n3x=qy=1+qqsa=q2+q+1
c = n − 4 , x = 1 + q ∗ q , y = − q − q ( 1 + q ∗ q ) , s a = q 3 + q 2 + 2 q + 1 c=n-4,x=1+q*q,y=-q-q(1+q*q),sa=q^3+q^2+2q+1 c=n4x=1+qqy=qq(1+qq)sa=q3+q2+2q+1
……

通过归纳可以得到随着层数的降低,sa一定是逐渐增加的,并且每次的迭代都是最优的,所以当迭代到c=1时,得到的sa一定也是最优的。

证明不一定正确,欢迎大家前来交流。


当然,不放心的话也可以
(1)求出 x > 0 x > 0 x>0 的第一个解,然后求出y,即

  • b / = d b/=d b/=d
  • x = ( x 0 % b + b ) % b x = (x_0 \% b + b) \% b x=(x0%b+b)%b

(2)求出 y > 0 y > 0 y>0 的第一个解,然后求出x
(3)求出 y < 0 y < 0 y<0 的第一个解,然后求出x
(4)求出 x < 0 x < 0 x<0 的第一个解,然后求出y
通过比较上面4组x,y绝对值的大小得出最优的组合。

这样求解出来的x,y的abs和也一定是最优的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2200051.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI的历史、现状与理论基础

在本篇文章中&#xff0c;我们将深入探讨人工智能&#xff08;AI&#xff09;的起源、现状以及理论基础&#xff0c;为读者提供一个全面的理解框架。 I. 引言 人工智能&#xff08;AI&#xff09;作为一门跨学科的研究领域&#xff0c;其目标是模拟、延伸和扩展人的智能。本文…

是德(KEYSIGHT) N9040A、N9040B 信号分析仪

Keysight N9040B 的特性和规格包括&#xff1a; 功能性 3 Hz 至 8.4、13.6 或 26.5 GHz&#xff1b;使用是德科技智能混频器将频率扩展至 110 GHz&#xff0c;使用其他供应商的混频器将频率扩展至 THz10 MHz&#xff08;标准&#xff09;、25、40、255 或 510 MHz 分析带宽全…

第十八篇:一文说清楚ICMP的底层原理

作为程序员或者网络工程师&#xff0c;有时候无法访问对方主机&#xff1b;导致这个现象的有很多原因&#xff0c;那要排查具体的网络原因&#xff0c;可能会用到ping的指令。而ping的底层实现是互联⽹控制报⽂协议&#xff08;ICMP&#xff09;。 ICMP 全称是 Internet Contr…

清华系“仓颉”来袭:图形起源:用AI颠覆字体设计,推动大模型商业化落地

大模型如何落地&#xff1f;又该如何实现商业化&#xff1f;这一议题已成为今年科技领域的焦点话题。 在一个鲜为人知的字体设计赛道上&#xff0c;清华创业公司“图形起源”悄然实现了商业变现&#xff1a;他们帮助字体公司将成本降低了80%&#xff0c;生产速度提升了10倍以上…

网站优化门槛低了还是高了?

自从2015年刚接触网站时&#xff0c;从一无所知到现在无人指导&#xff0c;一直跌跌撞撞走过来&#xff0c;当年花了1500元找了广东一个网友用织梦CMS做了一个门户网站&#xff0c;记得那时一星期没下楼&#xff0c;把网站折腾的千疮百孔&#xff0c;而终逐步熟悉网站建设与搜索…

手机怎样改网络ip地址?内容详尽实用

随着网络技术的发展&#xff0c;更改手机IP地址已成为一种常见需求。本文将详细介绍如何在不同网络环境下更改手机IP地址&#xff0c;包括移动网络和WiFi网络&#xff0c;以及同时适用于两种网络的方法&#xff0c;内容详尽实用&#xff0c;干货满满。 一、适用于移动网络&…

sentinel微服务部署

一.启动nacos和redis 1.查看是否有nacos和redis docker ps -a2.启动nacos和redis docker start nacos docker start redis-6379 docker ps 二.使用openfeign项目 这里看我另一个博客OpenFeign微服务部署-CSDN博客&#xff0c;我把SpringSessiondemo复制后改为sentinel1…

钡铼技术R10工业4G路由在智能交通中的应用

随着物联网技术的迅猛发展&#xff0c;智能交通系统&#xff08;Intelligent Transportation System, ITS&#xff09;正逐渐成为现代城市交通管理的重要组成部分。智能交通系统通过集成先进的信息技术、通信技术、传感技术以及计算机处理技术&#xff0c;实现对交通信息的实时…

抖店API接口系列(商品详情数据),Json数据格式参考

抖店API接口系列中的商品详情数据接口允许第三方应用通过编程方式访问抖音小店的商品数据。这些数据通常包括商品的基本信息、价格、库存、用户评价等&#xff0c;并且会以JSON数据格式返回。以下是一个抖店商品详情数据JSON格式的参考示例&#xff1a; { "status":…

共享购模式:绿色积分引领消费新潮流

绿色消费浪潮席卷全球&#xff0c;绿色积分作为一种创新的激励机制&#xff0c;正受到越来越多消费者的青睐。在众多消费模式中&#xff0c;共享购模式凭借独特的绿色积分体系&#xff0c;不仅推动了绿色消费&#xff0c;还为消费者带来了更多实惠与额外收益&#xff0c;成为市…

解数独Python

怎样解数独&#xff1f; Python def setBoardFunc(puz): global grid print("Original Sudoku") for i in range(0, len(puz), 9): row puz[i:i9] temp [] for block in row: temp.append(int(block)) g…

简单理解程序地址空间:Linux 中的内存映射与页表解析

ps: Linux操作系统对于程序地址&#xff0c;物理地址的处理&#xff0c;对于源码&#xff0c;我也看不大懂&#xff0c;只是截取当我们进程发生正常缺页中断的时候的调用情况。本文中所有的源码都是进行截取过的&#xff0c;如果大家感兴趣可以去下载源码。 在Linux 操作系统 …

【Linux】wsl2安装ubuntu并移动安装位置

本文首发于 ❄️慕雪的寒舍 1.启用wsl 首先是启用你的wsl&#xff0c;参考本站wsl安装centos8中的教程; 启用wsl后&#xff0c;更新一下&#xff0c;并设置版本为2&#xff1b; wsl --update wsl --set-default-version 2 # 设置wsl版本为2&#xff0c;不然可能安装失败2.安…

【FPGA开发】Modelsim仿真精度的坑

问题所在 最近在使用黑金的AXU3EG板卡对着正点原子ZYNQ7020的例程进行移植学习。但在编写tb代码以及使用modelsim进行仿真时出了问题&#xff0c;发现我的实际波形与正点的对不上&#xff0c;仔细测量一下波形发现&#xff0c;我的系统时钟是6ns周期&#xff0c;而不是理想中的…

某象异形滑块99%准确率方案

注意,本文只提供学习的思路,严禁违反法律以及破坏信息系统等行为,本文只提供思路 如有侵犯,请联系作者下架 该文章模型已经上线ocr识别网站,欢迎测试!!,地址:https://yxlocr.windy-rain.cn/ocr/slider/6 所谓的顶象异形滑块,是指没有采用常规的缺口,使用各种形状的…

20.安卓逆向-frida基础-hook分析调试技巧2-hookDES

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;图灵Python学院 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要盲目相信。 工…

MEMS 课本习题(1)

Chapter 5 Lump Modeling 为了将机械系统转换为等效电路&#xff0c;我们需要将各个机械元件转换为相应的电气元件。以下是机械元件和其电气等效元件的对照关系&#xff1a; 质量&#xff08;m&#xff09; - 转换为 电感&#xff08;L&#xff09;弹簧&#xff08;k&#xff…

SD入门教程一:Stable Diffusion 基础(技术篇)

前言 在开篇的时候就大致讲了SD和VAE&#xff0c;那么今天我们具象化地再来讲讲Stable Diffusion&#xff08;稳定扩散&#xff09;。 严格说来它是一个由几个组件&#xff08;模型&#xff09;构成的系统&#xff0c;而非单独的一个模型。我以最常见的文生图为例&#xff0c;…

PCL 计算3DSC并可视化

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 法线计算 2.1.2 3DSC特征计算 2.1.3 可视化3DSC直方图 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接&#xff1a; PCL点云算法与项目实战案例汇总&#…

【C++】——继承【上】

P. S.&#xff1a;以下代码均在VS2019环境下测试&#xff0c;不代表所有编译器均可通过。 P. S.&#xff1a;测试代码均未展示头文件stdio.h的声明&#xff0c;使用时请自行添加。 博主主页&#xff1a;Yan. yan.                        …