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

(一)欧几里得算法又称辗转相除法,是求解两个数的最大公约数的算法,基本定义为:

a=qb+r,其中a,b,q,r都是整数,则:gcd(a,b)= gcd(b,r)

利用递归实现该算法:

long long gcd(int a,int b)
{
    if(b==0) return a;
    else return gcd(b,a%b);
}

辗转相除法的应用:(水题)

nefu 116:两仪剑法 http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=116

题目分析:

由题意知:该题是要求M和N的最小公倍数,由于数据较大,正常用会导致数据溢出而WA,所以要利用该求最小公倍数的公式变形,先去除,再去乘,来进行数据范围的控制,公式为:


则代码实现如下:

#include 
#include 

using namespace std;

long long gcd(int a,int b)
{
    if(b==0) return a;
    else return gcd(b,a%b);
}

int main()
{
    int m,n;
    while(scanf("%d%d",&m,&n)!=EOF)
    {
        printf("%lld\n",(m/gcd(m,n))*n);
    }
    return 0;
}

(二)扩展欧几里得算法基本定义:

ab不全为0,则存在整数xy,使得 gcd(a,b)= xa + yb

拉梅定理:用欧几里得算法计算两个正整数的最大公因子时,所需的除法次数不会超过两个整数中较小的那个十进制数的倍数的5倍。

拉梅定理推论:求两个正整数a,b,a>b 的最大公因子需要O(log2a)3次的位运算。

由扩展欧几里得的推论:如果gcd(a,b)=1,则称ab互素。

整数a和b互素的充分必要条件:存在整数xy,使得xa+yb=1 。

扩展欧几里得算法实现:

typedef long long int64;
using namespace std;

int64 exgcd(int64 m,int64 & x,int64 n,int64 & y)  //Extend Euclid
{
    int64 x1,y1,x0,y0;
    x0 = 1;y0 = 0;
    x1 = 0;y1 = 1;
    int64 r=(m%n+n)%n;
    int64 q=(m-r)/n;
    x=0;y=1;
    while(r)
    {
        x=x0-q*x1;
        y=y0-q*y1;
        x0=x1;
        y0=y1;
        x1=x;
        y1=y;
        m=n;
        n=r;
        r=m%n;
        q=(m-r)/n;
    }
    return n; //返回值为m和n的最大公约数,修改后的x和y的值是所求值
}
扩展欧几里得算法应用:

POJ 1061:青蛙的约会 http://poj.org/problem?id=1061

题目分析:设两只青蛙跳了t步后相遇,A蛙的坐标为:x+mt ,B蛙的坐标为:y+nt 。两蛙相遇的条件为:  ,公式变形为:  设 ,求满足 的最小t(t>0),即求一次同余方程  的最小正整数解。具体求解过程为3步:

(1)写出方程,用扩展欧几里得函数求解,即 此时X是一个解,但不是最后的解。

(2)若(x-y)%gcd(n-m,L)==0, 则有解(指xy都有解)。

(3)有解后,设M=gcd(n-m,L),X=X(x-y)/M

然后:(X%(L/M)+(L/M))%(L/M)  就是最后的解,即为本题的t的值。

代码实现如下:

#include 
#include 

typedef long long int64;
using namespace std;

int64 exgcd(int64 m,int64 & x,int64 n,int64 & y)  //Extend Euclid
{
    int64 x1,y1,x0,y0;
    x0 = 1;y0 = 0;
    x1 = 0;y1 = 1;
    int64 r=(m%n+n)%n;
    int64 q=(m-r)/n;
    x=0;y=1;
    while(r)
    {
        x=x0-q*x1;
        y=y0-q*y1;
        x0=x1;
        y0=y1;
        x1=x;
        y1=y;
        m=n;
        n=r;
        r=m%n;
        q=(m-r)/n;
    }
    return n; //返回值为m和n的最大公约数,修改后的x和y的值是所求值
}

int main()
{
    int yy;
    int64 r,t;
    int64 x,y,m,n,l;
    int64 ar,br;
    cin>>x>>y>>m>>n>>l;
    int64 M=exgcd(n-m,ar,l,br);
    if((x-y)%M||m==n)
    cout<<"Impossible"<






你可能感兴趣的:(数论)