欧几里德和扩展欧几里德详解 以及例题CodeForces 7C

欧几里德定理:

对于整数a,b来说,gcd(a, b)==gcd(b, a%b)==d(a与b的最大公约数),又称为辗转相除法

证明:

因为a是d的倍数,b是d的倍数;所以a%d==0;b%d==0;

设k=a/b;r=a%b;则 a=k*b+r; 

由上得出:r=a-k*b;

因为a和b都是d的倍数,所以(a-k*b)也是d的倍数,所以r也是d的倍数;

所以gcd(a, b)==gcd(b, a%b)==d

而为什么要证明gcd(a, b)==gcd(b, a%b)==d这个式子成立呢?

其实证明gcd(a, b)==gcd(a, a%b)==d这个式子成立也是可以的,因为a也是d的倍数,但是在进行递归之前要进行一步操作,就是判断a与b的大小,如果a<b,就没办法进行递归或者循环求最大公约数,那么如果a<b,就交换a与b,之后就不用交换了,因为已知a>b,那么a%b<a必定成立;

事实发现证明gcd(a, b)==gcd(b, a%b)==d这个式子会缩小处理的数据的范围;

欧几里德应用:

用来求a,b的最大公约数。

代码实现:

//gcd(a, b)==gcd(a, a%b)==d,也成立
#include<stdio.h>
int main()
{
    int m, n, r, t;
    scanf("%d%d", &m, &n);
    if(m<n)
    {
        t=m;
        m=n;
        n=t;
    }
    while(r=m%n, r!=0)
    {
        m=m;
        n=r;
    }
    printf("%d\n", n);
    return 0;
}

  

//gcd(a, b)==gcd(a, a%b)==d递归
int gcd(int m, int n)
{
    return n?gcd(n, m%n):m;
}

  

//gcd(a, b)==gcd(a, a%b)==d递归
int gcd(int m, int n) { if(m%n==0) return n; else return gcd(n, m%n); }

  

//gcd(a, b)==gcd(b, a%b)==d 循环
while((r=m%n)!=0)
{
  m=n;
  n=r;
}

扩展欧几里德定律: 

对于不完全为0的非负整数a,b;gcd(a, b)表示a, b的最大公约数,必定存在整数对x,y,满足a*x+b*y==gcd(a, b);

证明:

a*x1+b*y1=gcd(a, b); 

b*x2+(a%b)*y2=gcd(b, a%b);

因为由欧几里德定理知:gcd(a, b)==gcd(b, a%b)

所以a*x1+b*y1=b*x2+(a%b)*y2;     因为r=a%b,   r =a-k*b所以==>

a*x1+b*y1=b*x2+(a-k*b)*y2;         因为k=a/b;所以 ==>

a*x1+b*y1=b*x2+(a-(a/b)*b)*y2;     展开得到  ==>    

a*x1+b*y1=b*x2+a*y2-b*(a/b)*y2;  转换得到      ==>

a*x1+b*y1=a*y2+b*(x2+(a/b)*y2);

观察上式可知 x1=y2, y1=x2-a/b*y2;

由此可知x1,y1是由x2,y2得出来的,由此类推x2,y2是由x3,y3得出来的,

那什么时候是终止呢?也就是递归gcd(a, b)中b=0时;也就是说此时a的值就是要求得最大公约数

即gcd(a, 0)此时由扩展欧几里得定律a*x+b*y==gcd(a, b)知 a*x+b*y=a;

解出x=1, y=0;

此时就是递归终止的地方:

扩展欧几里德应用:

就我目前所知的就是:求解不定方程;如a*x+b*y=c; 已知a, b, c的值求x和y的值

那么问题来了,如何将扩展欧几里德定律应用在求解不定方程呢?

可以这样转化   a*x+b*y=gcd(a, b)*c/gcd(a, b);

最后转化为 a*x/(c/gcd(a, b))+b*y/(c/gcd(a, b))=gcd(a, b); 最后求出的解x0,y0乘上c/gcd(a, b)就是最终的结果了

x1=x0*c/gcd(a, b);

y1=y0*c/gcd(a, b);

代码实现:  举例说明:http://codeforces.com/problemset/problem/7/C

#include<stdio.h>
long long exgcd(long long a, long long b, long long &x, long long &y);
int main()
{
    long long a, b, c, ans, x, y;

    while(scanf("%lld%lld%lld", &a, &b, &c)!=EOF)
    {
        ans=exgcd(a, b, x, y);
        if(c%ans==0)
        {
            x=-x*c/ans;
            y=-y*c/ans;
            printf("%lld %lld\n", x, y);
        }
        else
            printf("-1\n");
    }
    return 0;
}
long long exgcd(long long a, long long b, long long &x, long long &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    long long r=exgcd(b, a%b, x, y), t;
    t=x;
    x=y;
    y=t-(a/b)*y;
    return r;
}

 但这只是求得了一组解x1,y1

对于x,y对应的解集是:

x=x1+b/gcd(a, b)*t;

y=y1-b/gcd(a, b)*t;

但是我证明不出来,如果哪位大神懂得,可以给我说说!

 

posted @ 2015-10-29 10:59  花开须臾  阅读(1040)  评论(0编辑  收藏  举报