【hiho一下-95】 扩展欧几里得算法

来源:互联网 发布:网络与新媒体概论笔记 编辑:程序博客网 时间:2024/06/05 03:43

      例题是hiho的一道题:

      题目

      这道题主要用到了欧几里得扩展算法,并且求一下最小正整数解就好了,没什么特别的。不过,再次学习了一下欧几里得扩展算法,有了更深的理解。欧几里得扩展算法可以有两种形式:

      1. ax + by = c = bx +(a%b)y 证明很容易,根据欧几里得算法,设t=(a,b),a=k1*t, b=k2*t, (a%b)=k3*t,那么c也能表示成t的倍数,只要修改x和y,就一定能相等。

      2. a*t1(k-1) + b*t2(k-1) = t3(k-1)

          a*t1(k) + b*t2(k) = t3(k)

          a*t1(k+1) + b*t2(k+1) = t3(k+1)

          t3(k+1) = t3(k-1)%t3(k)

      只要一直迭代下去,直到t3(k+1)=0,那么t3(k)就是最小公约数。有人可能会迷惑,这个公约数是谁和谁的呢?那么如果我们设置t3(0)=a,t3(1)=b,那么就是(a,b),由此可以得到最初的两个式子:

      a*1 + b*0 = a

      a*0 + b*1 = b

      只要推理一下,就能得到递推公式:

      t3(k+1) = t3(k-1) % t3(k)

      t1(k+1) = t1(k-1) - t1(k)*tmp

      t2(k+1) = t2(k-1) - t2(k)*tmp

      tmp = t3(k-1)/t3(k)

      证明方法请自行百度一下:证明

      下面是题目的代码:

////  hiho.cpp//  hiho////  Created by lhq on 16/4/25.//  Copyright © 2016年 lhq. All rights reserved.//#include <iostream>#include <stdio.h>#include <math.h>using namespace std;/* ax + by = gcd = bx + a%by = bx + (a - a/b * b)y = ay + (x - a/b*y)b  v1 > v2 s1 + v1*t = s2+ v2*t - km (v1-v2)*t + mk = s2 - s1  v2 > v1 s2 + v2*t = s1 + v1*t -km (v2-v1)*t + km = s1 - s2  at + mk = gcd 求t,k   t,k > 0 且为整数  ax + by = gcd a*(x + b/gcd * u) b*(y - a/gcd * u)  求最小的x  */// ax + by = c  a = b , b = a%b 直到b = 0 主动改变a,blong long gcd_ex(long long& x, long long& y, long long a, long long b){    if(b == 0){        x = 1;        y = 0;        return a;    }    long long tmp = gcd_ex(x, y, b, a%b);    long long tmpy = y;    y = x - (a/b)*y;    x = tmpy;    return tmp;}// at1 + bt2 = t3   t3 = t1%t2 直到t3=1 主动改变x,y  注意:初始值设置为,t3(k-1)=a, t3(k)=b,所以肯定能得到t3=(a,b)long long gcd_ex_2(long long& x, long long& y, long long a, long long b){    long long to_1,to_2,to_3;    long long tm_1,tm_2,tm_3;    long long tn_1,tn_2,tn_3;    //不存在最大公约数    if(a == 0 || b == 0){        x = y = 0;        return 0;    }    to_1 = 1; to_2 = 0; to_3 = a;    tm_1 = 0; tm_2 = 1; tm_3 = b;    for(tn_3 = to_3%tm_3; tn_3!=0; tn_3=to_3%tm_3){        long long tmp = to_3 / tm_3;        tn_1 = to_1 - tmp * tm_1;        tn_2 = to_2 - tmp * tm_2;                to_1 = tm_1; to_2 = tm_2; to_3 = tm_3;        tm_1 = tn_1; tm_2 = tn_2; tm_3 = tn_3;    }    x = (tm_1%(b/tm_3) + b/tm_3)%(b/tm_3);   //最小正整数解    y = (tm_2%(b/tm_3) + a/tm_3)%(a/tm_3);   //最小正整数解    return tm_3;}int main(){    long long s1,s2,v1,v2,m;    long long x,y,a,b,c,gcd;    while(cin>>s1>>s2>>v1>>v2>>m){        a = (v1 - v2);        b = m;        c = (s2 - s1);        if(a<0){            a = -a; c = -c;        }        if(c<0){            c += m;        }        gcd = gcd_ex_2(x, y, a, b);//        gcd = gcd_ex(x, y, a, b);        if(c % gcd){            cout<<-1<<endl;        }else{            b = b/gcd;            x = (x*c/gcd)%b;            if(x>0){                cout<<x<<endl;            }else{                while(x<0){                    x += b;                }                cout<<x<<endl;            }        }    }    return 0;}


0 0