求解最大公约数——欧几里得算法及其(解同余方程)拓展

最大公约数的求法中最过著名的莫过于欧几里得辗展相除法,它有两种形式(递归与非递归,其实是一样的,任何递归都可以写成非递归),下面看看GCD的实现代码:

/***求a,b最大公约数***/

long long gcd(long long a, long long b) {

if(b == 0)

return a;

else

return gcd(b, a % b);

}


證明过程(摘自维基百科:zh.wikipedia.org/wiki/輾轉相除法)

欲證

先設

可得且知

表示d是b,r的公因數,但

所以

可得且知

表示e是a,b的公因數,但

所以

可得知



扩展的欧几里德算法是求如a * x + b * y = (a, b) 这样的整数解的,可以仿照欧几里德算法得出答案。程序如下:

/***扩展的欧几里德算法a*x + b*y = Gcd(a,b)的一组整数解,结果存在x,y中***/

void extend_gcd(long long a, long long b, long long&
x, long long &y) {

if(b == 0) {

x = 1;

y = 0;

return;

}

extend_gcd(b, a % b, x, y);

long long tmp = x;

x = y;

y = tmp - a / b * y;

}

上述程序只是得到了一组解,很显然解是不唯一的:x增加b, y减少a一定是原方程的一组解:

a *  (x + b)  + b * (y - a) = a * x + b * y = (a, b)。

然而在应用上,往往并不是如此简单,很多时候会求解不定方程a * x + b * y = n。这个时候还是应用上面的算法:

  1. 求(a,b), 设c = (a,b),如果! c|n,则不存在整数解。因为将上式左右两边都除以c,可以知道,左边为整数,右边为非整数,故矛盾。
  2. 将左右两边同时除以c,设得到新的方程为a‘ * x + b‘ * y = n‘,应用上述算法求a‘ * x + b‘ * y = 1的解(由第一步知道(a‘,b‘) = 1)。设结果为x‘, y‘。
  3. x = x‘ * n‘ , y = y‘ * n‘是方程a * x + b * y = n。这个比较好理解,将a‘ * x + b‘ * y = 1两边同时扩大n‘倍就行了。
  4. x = x‘ * n‘ + t * b, y = y‘ * n‘ - t * a(t为整数)是原方程a * x + b * y = n的所有解。

线性同余方程实现代码:

/*
  扩展欧几里得定理
  扩展欧几里得定理:对于两个不全为0的整数a、b,必存在一组解x,y,
  使得ax+by==gcd(a,b);
  拓展欧几里得实现
  下面面的程序中,x和y用全局变量保存
  int gcd(int a,int b)
  {
    int t,d;
    if(b==0)
    {
        x=1;
        y=0;
	//此时b==0,也就是说gcd(a,0)==a。原式变为ax+by==a=gcd(a,b)--> x==1,y==0
        return a; //返回a,b最大公约数的值
    }
    d=gcd(b,a%b); //欧几里得求最大公约数应用
    t=x;
    x=y;
    y=t-(a/b)*y;  //不明处2
    return d;     //返回a,b最大公约数的值
  }
  //不明处2 解释 ax+by==gcd(a,b)(1)
    说明规则,x,y表示第一次递归时的值,x1,y1表示第二次递归时的值。
	那么gcd(a,b)==gcd(b,a%b),同时都代入式1,
	有ax+by==b*x1+(a%b)*y1。将右边变形一下
    b*x1+(a%b)*y1==b*x1+(a-(a/b)*b)*y1==a*y1+b*(x1-(a/b)*y1),
	最终得到ax+by==a*y1+b*(x1-(a/b)*y1)
    也就是说:
	上一深度的x等于下一深度的y1,
	上一深度的y等于下一深度的x1-(a/b)*y1。
   *需要注意,上面推导时用的除法都是整型除法

    因此,得到了不定式ax+by==gcd(a,b)的一组解,x、y。
    那么对于一般的不定式ax+by==c,它的解应该是什么呢。
	很简单,x1=x*(c/gcd(a,b)),y1=y*(c/gcd(a,b)) 

	再深入一点,就解出这么一组解其实一般来说是解决不了什么问题的,
	我们现在要得到所有的解,那么这所有的解究竟是什么呢?
	假设d=gcd(a,b). 那么x=x0+b/d*t; y=y0-a/d*t;其中t为任意常整数。

*/ 

#include<stdio.h>
#include<stdlib.h>

/*
  求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解。
  即求ax=mb+r 1=nb+r
  变形ax+(n-m)b=1,此方程即拓展欧几里德的应用ax+by=gcd(a,b),(n-m相当于y)
  事实上ax ≡1(mod b) 有解的必要条件是gcd(a,b)|1,即gcd(a,b)=1;
  使用拓展欧几里得可知 ax+by=1(x,y是整数)
*/

int  Extragcd(int a,int b,int *x,int *y)
{
	int d,t;
	if(b==0)  //递归调用终止条件,当根据欧几里得辗转相除法则,余数为0停止
	{
		*x=1;
		*y=0;
		return a;
	}
	else
	{
		d=Extragcd(b,a%b,x,y);
		t=*x;     //根据下一个x1,y1的值,倒推前一个x,y的值
		*x=*y;
		*y=t-a/b*(*y);
		return d;
	}
}

int main()
{
	int a,b,x,y;
	int ans;
	freopen("mod.in","r",stdin);
	freopen("mod.out","w",stdout);
	scanf("%d%d",&a,&b);
	ans=Extragcd(a,b,&x,&y);
	if(ans!=1) return 0;
	//根据若x是方程的一个解,则方程的所有解为x+k*b k为整数
    x=x%b; //保证最小的正整数解x ,且x属于{0,1,2,3...b-1}
    while(x<=0)
        x+=b ;
    printf("%d\n",x);
    return 0;
}
时间: 2024-08-01 22:35:28

求解最大公约数——欧几里得算法及其(解同余方程)拓展的相关文章

扩展欧几里得算法详解

一:欧几里得算法(辗转相除法) 基本算法:设a=qb+r,其中a,b,q,r都是整数,则gcd(a,b)=gcd(b,r),即gcd(a,b)=gcd(b,a%b). 证明: a可以表示成a = kb + r,则r = a mod b 假设d是a,b的一个公约数,则有 d|a, d|b,而r = a - kb,因此d|r 因此d是(b,a mod b)的公约数 假设d 是(b,a mod b)的公约数,则 d | b , d |r ,但是a = kb +r 因此d也是(a,b)的公约数 因此(a

最大公约数-----欧几里得算法

欧几里得算法: 如果求两个数的最大公约数,那么最一般的求法是设置一个变量i=1,然后i不断加一,如果i加到某个数后两个数都能整除这个数了,然后把这个变量保存下来,然后最后的结果中最大的就是最大公约数. 然而这种方法时间复杂度可想而知有多高,所以一般情况瞎并不用这种方法,那么就有下面的欧几里得算法: 输入:两个数 a,b 输出:两个数的最大公约数 c 欧几里得算法:(1)找出两个数中最大的和最小的,分别为tmax.tmin, (2)不断令设置一个变量t代表tmin,tmin赋值为tmax  mod

求最大公约数——欧几里得算法

欧几里得算法的原理:基于这样一种观察,两个整数x和y(x>y)的最大公约数等同于y和(x%y)的最大公约数: 数t整除x和y,当且仅当t整数y和(x%y):这是因为:x = t*y + x%y; 具体代码如下: #include <iostream> #include <stdlib.h> using namespace std; int gcd(int x, int y) { cout << x << " " << y

查找两个数的最大公约数——欧几里得算法

欧几里得算法: 百度百科:欧几里德算法又称辗转相除法,是指用于计算两个正整数a,b的最大公约数.应用领域有数学和计算机两个方面.计算公式gcd(a,b) = gcd(b,a mod b). 代码实现如下: import java.util.Scanner; public class Main { public static void main(String[] args) { //这里输入的a,b均是大于0的. Scanner cin = new Scanner(System.in); whil

求最大公约数的欧几里得算法与其伪代码

最大公约数的欧几里得算法 a,b最大公约数(Greatest Common Divisor),就等于b,a%b的最大公约数,公式如下 gcd(a,b)=gcd(b,a%b) gcd(a,b) = gcd(b,a % b) gcd(a,b)=gcd(b,a%b) 摘自 欧几里得算法(求解最大公约数的优质方法)以及原理拓展 用伪代码实现此算法 Begin 输入 A,B A对B取余,结果赋值为R 若R=0,则B是最大公约数 若R不等于0,则以B为A,以R为B循环上一步 手动检测运算截图 原文地址:ht

数论及其应用——欧几里得算法

欧几里得是数论当中最基本的定理,以其为基础的拓展欧几里得算法在解决同余方程.求模逆元等问题. 首先来介绍几个概念,数论当中一些基本的概念其实在小学就学过,但是很长一段时间并没有用到它们,因此这里再拿出来温习一下. 我们常常用a|b来表示b能够整除a(b > a),即b/a是整数,但是“|”在使用的过程中容易和绝对值.几何定义符.条件概率混淆,所以,这里我们用a\b来表示a能够整除b. 约数:如果b\a,则称b是a的约数. 倍数:如果b\a,则称a是b的倍数. 最大公约数:gcd(a,b) = m

欧几里得算法与扩展欧几里得算法

欧几里得算法基于这样一个 GCD 递归定理: $gcd(a, b) = gcd(b, a\bmod{b}) $ 证明如下: 假设 $a > b$, $a = kb + r(0 <= r < b)$, 即 $a\bmod{b} = r$. 若有 $d \mid a$ 且 $d \mid b$, 必然有 $d \mid a - kb$, 即 $d \mid r$. 由此得知, $a$ 与 $b$ 的所有公约数必然是 $b$ 与 $r$ 的公约数. 若有 $d \mid r$ 且 $d \mi

对拓展欧几里得算法的一点理解

首先需要明确的一点是:这是一种算法,而非一个证明题. 算法的需求与数学证明题是不一样的,数学证明题要求严谨完整,而算法只需要证明我用到的某个的性质成立即可,相当于是“恰好发现了这一点”. 于是对于拓展欧几里得,我们是从欧几里得算法中发现了一个递推的性质,从而受到启发,产生猜想:可不可以利用递推求出二元一次方程的解? 我们把猜想建立在欧几里得算法之上,利用该算法的递推过程,贯穿该过程来得到想要解决问题的答案. 也就是说,我们仅仅需要证明我们得到的答案是正确的,而并非深刻挖掘欧几里得算法的过程. 拓

如何使用拓展欧几里得算法求解模线性方程组(详解)

式子a≡b(mod n)称为a和b关于模n同余,它的充要条件是a-b是n的整数倍,即a-b=zn(其中z取整数). 而模线性方程组ax≡b(mod n)可以写成ax-b=zn(其中z取整数),移项可得 ax-zn=b,也即二元一次方程ax+by=c的形式,利用拓展欧几里得算法(extgcd)可以求解该方程是否有解及其一组解,并可根据该组解写出解系,进而求出一个特解,比如最小正整数解. 下面给出拓展欧几里得算法的程序. 1 typedef long long LL; 2 void extgcd(L