首页 > 代码库 > 扩展欧几里德算法

扩展欧几里德算法

本来数学就不好,看到LRJ的数学专题直接跪了,上网百度了一下才知道扩展欧几里德算法的证明过程。

首先说一下朴素欧几里德算法,就是辗转相除法,很简单。

int gcd(int a,int b){
    return b == 0 ? a : gcd(b,a % b);
}

下面主要说一下扩展欧几里得算法。

给出a,b 求 x,y使得 a * x + b * y = gcd(a,b);

我们不妨设a > b,且 x > y 

那么当b = 0 的时候 gcd(a,b) = a,因此 x = 1 , y = 0;

如果b != 0 的时候,我们知道

ax1 + by1 = gcd(a,b) = bx2 + (a % b)y2;(根据朴素欧几里德)

我们化简一下这个式子

ax1 + by1 = bx2 + (a - (a / b) * b)y2;

ax1 + by1 = bx2 + a * y2 - (a / b) * b * y2;

ax1 + by1 = a * y2 + b * (x2 - (a/b) * y2);

因此 x1 = y2;

y1 = (x2 - (a/b) * y2);

也就是说每一层的x,y可以由上一层的x,y求出,递归终点为 b = 0;

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<list>
#include<string>
#include<cmath>
#include<sstream>
#include<ctime>
using namespace std;
#define _PI acos(-1.0)
#define INF 1 << 10
#define esp 1e-6
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pill;
/*===========================================
===========================================*/
void gcd(int a , int b , int & d,int &x ,int &y){
    if(!b){
        d = a;
        x = 1; y = 0;
    }
    else{
        gcd(b , a % b ,d, y , x);
        y -=  x * (a / b);
    }
}
int main(){
    int x,y,a,b,c;
    while(scanf("%d%d",&a,&b) != EOF){
          x = max(a,b);
          y = x;
          if(a < b)  /*保证a > b */
            swap(a,b);
          gcd(a,b,c,x,y); /*代表a * x + b * y = c */
          printf("(%d * %d) + (%d * %d) = %d\n",a,x,b,y,c);
    }
    return 0;
}


ps:另外,要求多组解的话,假设已经求了一组解为(x0,y0),设:a‘ = a / gcd(a,b), b‘ = b / gcd(a,b),那么其余任意解都可以写成(x0 + k * b‘ ,y0 - k * a‘);