IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 关于扩展欧几里得算法和乘法逆元的相关理解 -> 正文阅读

[数据结构与算法]关于扩展欧几里得算法和乘法逆元的相关理解

1.关于扩展欧几里得算法的理解

首先要先学会欧几里得算法(辗转相除法):

int gcd(int a, int b) {
?? ?return b ? gcd(b, a % b) : a;
}
/*
c = a % b;
a = b; b = c;
if b != 0 重复上述步骤
if b == 0 return a;
*/

然后去看扩展欧几里得算法:

几个关键点:

????????因为 ax + by = gcd(a, b)?
?? ??? ? ? ? ? ?bx1 + (a % b)y1 = gcd(b, a % b)
?? ??? ? ? ? ? ?gcd(a, b) = gcd(b, a%b)

?? ??? ? ? 所以 ax + by = bx1 + (a % b)y1
?? ??? ? ? 因为 a % b = a - b[a / b] ? ? ? ?(这里a / b是计算机的整除)
?? ??? ? ? 整理可得解为:
?? ??? ? ? x = y1;
?? ??? ? ? y = x1 - (a / b) * y1;

?? ??? ? ? 因为一开始只知道x和y,x1和y1是需要求的,那么我们根据上面发现的特性,发现需要从后往前不断求,
?? ??? ? ? 最后得出x和y,所以需要递归的思想。
?? ??? ? ? 递归出口是当b = 0时,x = 1,y = 0。(注意这里准确说是xn = 1,yn = 0)
?? ??? ? ? 此时x = 1,y = 0(即xn = 1,yn = 0)这个解就是最后的一组解,然后从后往前,不断的得出解,最后就得到了x和y的解

?? ??? ? ? 下面通过代码具体解释一下:


直观的代码:

void exgcd(int a, int b, int &d, int &x ,int ?&y)
//一开始从前往后不断递归的时候,其实只计算了a和b,int &x和int &y是从后往前返回的时候进行的相应赋值和计算
{
?? ?if ( !b )
?? ?{
? ? ? ? d = a;
?? ??? ?x = 1;
?? ??? ?y = 0; //这里是最后一组解(即xn = 1,yn = 0)
?? ??? ?return;
?? ?}
?? ?int x1,y1;
?? ?exgcd( b , a % b , d , x1 , y1 );
/*
这里x1和y1一开始从前往后递归时没有值,当从后往前返回时,得到了值(相当于得到了未来的值)然后通过下面的
x = y1;
y = x1 - ( a / b ) * y1;
这两行代码就得到了这层递归循环的x和y的值(即当前的值,但是当return返回后,又相当于上一层递归循环的未来的值)
?*/
?? ?x = y1;
?? ?y = x1 - ( a / b ) * y1;
?? ?return ;
}

简化的代码(不直观):

int exgcd(int a, int b, int &x, int &y)
{
? ? if (!b)
? ? {
? ? ? ? x = 1; y = 0;
? ? ? ? return a;
? ? }
? ? int d = exgcd(b, a % b, y, x);
?/*
?这里是我认为比较难想的地方,不直观,下面讲讲我的理解:
这行代码里int d = exgcd(b, a % b, y, x);的y,x一开始从前往后递归时没有值,当从后往前返回时,
y的地方相当于x1的位置,x的地方相当于y1的位置,那么从后往前返回时,返回的值会给y和x赋值,
y得到了返回的x1的值,x得到了返回的y1的值,因为:
x = y1;
y = x1 - ( a / b ) * y1;
所以x不用变,y现在等于x1,x现在等于y1
所以y = y - ( a / b ) * x 就得到了当前这层递归循环y应该的值
这样一来,这层递归循环的x和y的值就都得到了
然后int exgcd(int a, int b, int &x, int &y)这里是x和y的实参,所以刚才得出的x和y的值,
就会传给这里的int &x, int &y,然后继续返回。
? */
? ? y -= (a/b) * x;
? ? return d;
}

2.下面介绍乘法逆元的理解:

1.乘法逆元的作用
当a和b过大时,要进行取模操作,可以如下操作,
(a + b)% p = ((a % p) + (b % p)) % p;
(a - b)% p = ((a % p) - (b % p)) % p;
(a * b)% p = ((a % p) * (b % p)) % p;
但是(a / b)% p不遵循这个法则,所以 可以换一个思想,
(a / b)% p 等同于 (a * b的逆元) % p, 那么问题转化为求b的逆元
设b的逆元为x,则 (b * x) mod p = 1

2.乘法逆元的条件
因为(b * x) mod p = 1
所以 b * x - n * p = 1
即 b * x + n * p = 1

通过前面的学习,我们知道b * x + n * p = k有整数解的条件是
k是gcd(b, p)的整数倍,所以k % gcd(b, p) = 0
当 k = 1 时,1 % gcd(b, p) = 0
所以gcd(b, p) = 1 ,即b 和 p互质是有乘法逆元的充要条件

3.如何求乘法逆元
我们发现b * x + n * p = 1 里的x可以用前面学过的扩展欧几里得算法得到,
求最小逆元就直接x % p就可以了(x 和 p此时都是正数)。

4.求乘法逆元的代码

int inv(int b, int p) {
?? ?int x, y;
?? ?int gcd = exgcd(b, p, x, y);
?? ?if(1 % gcd != 0)?? ?return -1; //没有乘法逆元
?? ?p = abs(p);
    int ans = x % p;
    if(ans <= 0) ans += p;
?? ?return ans;?
?? ?/*
?? ?防止x是负数,
?? ?x是负数时,x % p + p 得到正数解
??  */
}

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-11 22:26:29  更:2022-03-11 22:30:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 14:53:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码