【Exgcd】扩展欧几里得算法
Description
欧几里德算法又称辗转相除法,是指用于计算两个正整数a,b的最大公约数。应用领域有数学和计算机两个方面。计算公式gcd(a,b) = gcd(b,a mod b)。
扩展欧几里德算法是用来在已知a, b,求解一组 x,y 使得:ax + by = gcd(p,q) (解一定存在,根据数论中的相关定理)。
本题任务:给定任意整数a,b,c,求方程 ax + by = c 的整数解,输出其中x是最小的正整数的一组。
Input
若干行,每行一组数据:a,b,c。他们都是int范围内的整数。
Output
每组数据输出一行,若给定方程没有整数解,输出"No solution",否则输出x是最小的正整数的一组。
Sample Input 1
1 1 1 1 2 1000 12 20 7 27 -45 18 6 15 9
Sample Output 1
1 0 2 499 No solution 4 2 4 -1
Hint
a,b,c在int范围内,且都不为0。
1.理论部分
欧几里得算法求最大公因数:
int gcd(int a, int b) { if(b == 0) return a; else return gcd(b, a%b); }
其中模运算可定义为:(以下除法都是指下取整除法)
a%b = a-a/b*b
扩展欧几里得算法:已知整数a、b,扩展欧几里得算法可以在求得a、b的最大公约数的同时,能找到整数x、y(其中一个很可能是负数),使它们满足贝祖等式
推导:由欧几里得算法:
ax + by = g //g=gcd(a,b) ==> bx' + (a%b)y' = g ==> bx' + (a-a/b*b)y' = g ==> bx' + ay' - a/b*by' = g ==> ay' + b(x'-a/b*y') = g ==> x=y', y=x'-a/b*y'
这样可以迭代求解,通过调用gcd(b, a%b)得到的x'和y'算出当前的x和y
由上述推导可直接写出如下的扩展欧几里得算法:
int Exgcd(int a, int b, int &x, int &y) { if(b == 0) { x=1, y=0; return a; } // gcd=a => gcd*1+0*y=a => x=1, y任取 int xx, yy; int gcd = Exgcd(b, a%b, xx, yy); x = yy; y = xx - a / b * yy; return gcd; }
可以不用xx和yy,代码稍加化简得到:
int Exgcd(int a, int b, int &x, int &y) { if(b == 0) { x=1; return a; } int gcd = Exgcd(b, a%b, y, x); y = y - a / b * x; return gcd; }
通过调用gcd = Exgcd(a, b, x, y),可得到一组满足ax+by=gcd的x和y的特解。
根据裴蜀定理,这样的x,y应该有无数对。
已知一对特解x0,y0,可由如下方式得到通解:
x = x0 + b / gcd * k
y = y0 - a / gcd * k(k属于整数)
证明:将x, y代入方程:
ax + by
= a(x0 + b / gcd * k) + b(y0 - a / gcd * k)
= a*x0 + b*y0 = gcd(a, b)
成立,证毕.
为了找到尽量多的通解,每次转移的步长应该尽量短,故式中a、b要/gcd
2.实践部分
利用扩展欧几里得算法实现本题:
#include<bits/stdc++.h> using namespace std; typedef long long LL; LL Exgcd(LL a, LL b, LL &x, LL &y) { if(b == 0) { x=1, y=0; return a; } // gcd=a => gcd*1+0*y=a => x=1, y任取 LL gcd = Exgcd(b, a%b, y, x); y = y-a/b*x; return gcd; } int main() { LL a, b, c, x, y, gcd; while(scanf("%lld%lld%lld", &a, &b, &c) == 3) { gcd = Exgcd(a, b, x, y); // 得到满足ax+by=gcd(a, b)的一组x, y if(c%gcd != 0) { puts("No solution"); continue; } a/=gcd, b/=gcd, c/=gcd; // 方程两边约分使得a, b互质gcd=1 if(b<0) a=-a, b=-b, c=-c, x=-x, y=-y; // 保证b为正,下面x0求出来才为正 // 方程改为(-a)x+(-b)y=(-c) // x,y符号不变,但为了使下一步算x0的x*c符号总体不变此处x,y符号改变 LL x0 = x*c; // x是ax+by=1的一个x, 所以x0=x*c是ax+by=c的一个x x0 = (x0 % b + b) % b; // ax+by=1 的通解: x=x0+k*b , y=y0-k*a, 代入方程展开即证 if(x0 == 0) x0 = b; // 保证为最小正整数 LL y0 = (c-a*x0)/b; // 确定了x0求y0 printf("%d %d\n", (int)x0, (int)y0); } return 0; }
-
原文地址:https://www.cnblogs.com/de-compass/p/12209058.html
- MySQL中的反连接(r12笔记第45天)
- Nginx配置多站点下的Proxy_cache或Fastcgi_cache缓存加速
- MySQL主从不一致的细小问题分析(r12笔记第62天)
- Linux在批量服务器管理中实用的PS1命令提示符格式
- Golang语言社区-并发模型和应用场景
- 翻过那座山,就能看见海|kubernetes让DBA更优雅地管理数据库
- 基于TextCNN的谩骂评论识别模型
- Golang语言社区-文件操作
- MySQL service启动脚本浅析(r12笔记第59天)
- 分享WordPress显示评论者IP的归属地及运营商信息的2种方案
- 解决dos2unix/unix2dos报错,并在家目录下生成u2dtmp*文件问题
- 【前沿】TensorFlow Pytorch Keras代码实现深度学习大神Hinton NIPS2017 Capsule论文
- Nginx通过二级目录(路径)映射不同的反向代理,规避IP+端口访问
- MySQL中批量初始化数据的对比测试(r12笔记第71天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 多目标优化拥挤距离计算
- matlab sort函数
- matlab结构体的创建与元素访问
- matlab赋值运算符等号
- Flutter中Widget 、Element、RenderObject角色深入分析
- PyTorch8:损失函数
- 浅谈ThreadLocal
- 三分钟完成 ubuntu16.04初始化,Java,maven,docker环境的部署
- VMware 安装运行 deepin 虚拟机 | 体验中国深度
- 单机KVM虚拟化快照定时创建删除快照
- 批量ping脚本
- 批量ssh信任脚本
- Oracle表级备份
- Linux脚本运行报错解决方法 bad interpreter: No such file or directory
- MySQLdump里的秘密,终于被我发现了