关闭

扩展欧几里得算法

标签: 欧几里得
505人阅读 评论(0) 收藏 举报

首先推荐两篇比较好的博客

http://blog.csdn.net/lincifer/article/details/49391175

http://blog.csdn.net/zhjchengfeng5/article/details/7786595

 

(然后下面便是一个蒟蒻的总结QAQ)

扩展欧几里德算法

基本算法:

  对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在整数对 x,y ,使它们满足贝祖等式: abgcd(abd

证明:

  设 a > b。

  1. 显然当 b = 0,gcd (a,b) = a 时, x = 1,y = 0;

  2. ab != 0 时

  原式:  abgcd(ab)(假设≥ b)

  • 当 b = 0 时有 gcd(ab)a, 此时 10

  • 当b不为0时, 根据欧几里得定理 gcd(abgcd(bmod b可得 abgcd(abgcd(bmod bbx′ (mod b)y,

  • 即 abbx′ (mod b)y′ bx′ (− ∗ b)y′  

  【我们知道 a % b = a - (a / b) * b(这里的 “/” 指的是整除,例如 5 / 2 = 2 , 1 / 3 = 0)】

  • 移项得 abbx′ (mod b)y′ ay′ b(x′ − b⌋ y)

   根据恒等定理,有 

   y′ 

   y x′ − by

 

  这有什么用呢? x′ 和 y′ 还是不知道呀.

  重新来看看我们得到的两个等式.

  x 和 y 是 gcd(a, b) = ax + by 的解,

  而 x’ 和 y’ 是在对 gcd(a, b) 按欧几里德算法进行一步后的结果对应的贝祖等式 gcd(b, a mod b) = bx′ + (a mod b)y′ 的解。

  也就是说, gcd(a, b) 对应的贝祖等式的解 x, y 可以由 gcd(b, a mod b) 对应等式的解 x’, y’ 计算得出。

    更进一步,对于任意不定式 ax′ + by′ = c, 只需要在等式 ax + by = gcd(a, b) = d 两边乘上 c /d 即可得到解为 x′ = x ∗ c / d, y′ = y ∗ c / d

扩欧代码:

1 viod exgcd(int a, int b, int &x, int &y) {
2     !b ? (x = 1, y = 0) : (exgcd(b, a % b, y, x), y -= (a / b) * x);
3 }

  

  扩展欧几里德有什么用处呢?

  求解形如 a * x +b * y = c 的通解,但是一般没有谁会无聊到让你写出一串通解出来,都是让你在通解中选出一些特殊的解,

  比如一个数对于另一个数的乘法逆元,什么叫乘法逆元?

     

  这里,我们称 x 是 a 关于 m 的乘法逆元

  这怎么求?可以等价于这样的表达式: a * x + m * y = 1

  看出什么来了吗?没错,当gcd(a , m) != 1 的时候是没有解的。这也是 a * x + b * y = c 有解的充要条件: c % gcd(a , b) == 0

 

  接着乘法逆元讲,一般,我们能够找到无数组解满足条件,但是一般是让你求解出最小的那组解,怎么做?

  我们求解出来了一个特殊的解 x0。那么,我们用 x0 % m其实就得到了最小的解了。为什么?

  可以这样思考:

   x 的通解不是 x0 + m * t 吗?

  那么,也就是说, a 关于 m 的逆元是一个关于 m 同余的,那么根据最小整数原理,一定存在一个最小的正整数,它是 a 关于m 的逆元,而最小的肯定是在(0 , m)之间的,而且只有一个,这就好解释了。

  可能有人注意到了,这里,我写通解的时候并不是 x0 + (m/gcd)*t ,但是想想一下就明白了,gcd = 1,所以写了跟没写是一样的,但是,由于问题的特殊性,有时候我们得到的特解 x0 是一个负数,还有的时候我们的 m 也是一个负数这怎么办?

  当 m 是负数的时候,我们取 m 的绝对值就行了,当 x0 是负数的时候,他模上 m 的结果仍然是负数(在计算机计算的结果上是这样的,虽然定义的时候不是这样的),这时候,我们仍然让 x0 对abs(m) 取模,然后结果再加上abs(m) 就行了,于是,我们不难写出下面的代码求解一个数 a 对于另一个数 m 的乘法逆元:

    

  ZOJ 3609 :http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4712 求最小逆元

  ZOJ 3593 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3593 求最小的步数,处理特殊一点就过去了

  POJ 1061 http://poj.org/problem?id=1061 青蛙的约会,裸的扩展欧几里得

  HDU 1576 http://acm.hdu.edu.cn/showproblem.php?pid=1576 做点处理即可

  HDU 2669 http://acm.hdu.edu.cn/showproblem.php?pid=2669 裸的扩展欧几里得


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int exgcd(int a,int b,int &x,int &y){
	int r,tmp;
	if(!b){x=1;y=0;return a;}
	else{
		r=exgcd(b,a%b,x,y);
		tmp=x;
		x=y;
		y=tmp-a/b*y;
		return r;
	}
} 
int main(){
	int i,j,k,m,n,a,b,x,y,z;
	scanf("%d%d%d%d",&a,&b,&x,&y);
	z=exgcd(a,b,x,y);
	printf("%d %d %d",z,x,y);
	return 0;
}
输入a和b 输出ax+by=gcd(a,b)的一组解(x,y)

倘若不是求ax+by=gcd(a,b)的解而是求ax+by=c的一组解
先判断 倘若c/gcd(a,b)不是整数那么无解
否则
把原方程求出来的解x,y变成x1,y1,而真正的一组解x,y为x=(c/gcd(a,b))*x1,y=(c/gcd(a,b))*y1

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:27716次
    • 积分:478
    • 等级:
    • 排名:千里之外
    • 原创:19篇
    • 转载:12篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档