1. 程式人生 > >extendGcd,即擴充套件歐幾里得演算法的C++模板化解釋

extendGcd,即擴充套件歐幾里得演算法的C++模板化解釋

       剛剛接觸感覺很高大上的“擴充套件歐幾里得演算法“,很鬱悶,研究了很久。現在感覺能夠套模板了,當然這樣是遠遠不夠的,不過先寫篇部落格記錄一下最近的動態。幫助自己記憶,也可以幫助大家理解下這個數學演算法,當然歡迎各位的斧正和指點,我將不斷努力!

       首先,明確我們要求ax+by=c中x,y的整數解(至於沒有解的情況下邊會討論)

       大家應該看到過ax+by=Gcd(a,b)的式子,現在我也不明白這是什麼,以下是我大概能夠死記硬背的(大家能學會的還是去學學原理)。

       先求gcd(a,b),程式如下:

typedef long long LL;
using namespace std;

LL gcd(LL a,LL b){
    while(a%b){
        LL temp=b;
        b=a%b;
        a=temp;
    }
    return b;
}
LL d=gcd(a,b);

後,a/=d,b/=d,c/=d;這裡有當c%d!=0是,ax+by=c不存在整數解(我也不知道為什麼,真的模板化了)

於是原式變成a'x+b'y=c'。據說那個擴充套件歐幾里得求的是a'x+b'y=1的解,給出extendGcd(a,b)的模板

void exGcd(LL a,LL b,LL &x,LL &y){
    if(b==0){
        x=1;y=0;
        return ;
    }
    exGcd(b,a%b,x,y);
        LL temp;
        temp=y;
        y=x-a/b*y;
        x=temp;
}
這裡不難得到修改後的x,y為方程a'x+b'y=1的解,那麼c'x0,c'y0就是a'x+b'y=c'的一組特解了,根據引數方程的性質,我們引入t(整數)來寫出x,y通解的引數方程x=c'x0-b't,y=c'y0+a't。

通常題目要求我們求問題的最小解,所以當x->0時,我們求出的t=c'x0/b(這裡是有誤差的,因為在C語言中的除不一定,事實上,我們可以判斷下x<0時,可以讓t=t+1。

下面來看一道典型的模板題吧。

poj 1061 

青蛙的約會
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 96453 Accepted: 18021

Description

兩隻青蛙在網上相識了,它們聊得很開心,於是覺得很有必要見一面。它們很高興地發現它們住在同一條緯度線上,於是它們約定各自朝西跳,直到碰面為止。可是它們出發之前忘記了一件很重要的事情,既沒有問清楚對方的特徵,也沒有約定見面的具體位置。不過青蛙們都是很樂觀的,它們覺得只要一直朝著某個方向跳下去,總能碰到對方的。但是除非這兩隻青蛙在同一時間跳到同一點上,不然是永遠都不可能碰面的。為了幫助這兩隻樂觀的青蛙,你被要求寫一個程式來判斷這兩隻青蛙是否能夠碰面,會在什麼時候碰面。
我們把這兩隻青蛙分別叫做青蛙A和青蛙B,並且規定緯度線上東經0度處為原點,由東往西為正方向,單位長度1米,這樣我們就得到了一條首尾相接的數軸。設青蛙A的出發點座標是x,青蛙B的出發點座標是y。青蛙A一次能跳m米,青蛙B一次能跳n米,兩隻青蛙跳一次所花費的時間相同。緯度線總長L米。現在要你求出它們跳了幾次以後才會碰面。

Input

輸入只包括一行5個整數x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。

Output

輸出碰面所需要的跳躍次數,如果永遠不可能碰面則輸出一行"Impossible"

Sample Input

1 2 3 4 5

Sample Output

4

程式碼如下

#include <iostream>
#include <cstdio>

typedef long long LL;
using namespace std;

LL gcd(LL a,LL b){
    while(a%b){
        LL temp=b;
        b=a%b;
        a=temp;
    }
    return b;
}

void exGcd(LL a,LL b,LL &x,LL &y){
    if(b==0){
        x=1;y=0;
        return ;
    }
    exGcd(b,a%b,x,y);
        LL temp;
        temp=y;
        y=x-a/b*y;
        x=temp;
}
int main()
{
    LL x,y,m,n,l,ans,key,t;
    while(~scanf("%I64d%I64d%I64d%I64d%I64d",&x,&y,&m,&n,&l)){
        /* (n-m)*ans+k*l=x-y;
         * n-m=a,ans=x,k=y,l=b,x-y=c;
         *   a*x+b*y=c;
         */
        LL a=n-m,b=l,c=x-y;
        LL d=gcd(a,b);
        //cout <<  d  <<endl;
        if(c%d) {printf("Impossible\n");continue;}

        a/=d;b/=d;c/=d;
        exGcd(a,b,ans,key);

        t=c*ans/b;
        ans=c*ans-t*b;
        if(ans<0)
            ans+=b;
        printf("%I64d\n",ans);
    }
    return 0;
}

學不好的我..只好這樣背公式了,希望以後能學好!