1. 程式人生 > >POJ 1061 :拓展歐幾里德

POJ 1061 :拓展歐幾里德

題目為POJ1061 青蛙的約會
題意大致為:
兩隻青蛙在不同的座標x,y,沿著一個方向跑環,每一次的移動距離為m,n,環的長為L,問能否成功會師即在某一時刻在同一座標點?輸出最小移動次數或“Impossible”
首先是拓展歐幾里德,歐幾里德演算法我們都知道,就是求兩個整數a,b的最大公約數gcd,而拓展歐幾里德演算法在得到gcd的同時,還求解出了ax+by=gcd的一組特解x0和y0,而運用拓展歐幾里德演算法時,大多都是需要從這個特解找出通解。

        ax0 + by0 = gcd                 ①
    => ax0+d + by0-d = gcd              ②
    => a(x0+d/a) + b(y0-d/b) = gcd      ③
    //因此,d最好為a和b的公倍數,那就不妨取d = a*b/gcd;
    => a(x0+t*d/a) + b(y0-t*d/b)=gcd    ④
    //t 為任意整數

故此,我們可以得到x和y的通解:

    x=x0+d/a*t
    y=y0+d/b*t

以上便是拓展歐幾里德的知識,那接下來回到問題:
第一隻青蛙座標為x,移動距離m,那 t 次之後它的座標就是 x+(t*m),同理,第二隻青蛙座標可表示為 y+(n*t),然後是根據題意建立等式求最小正整數 t :

    x+(t*m) = y+(n*t) + k*L

然後對上式進行變形:

    x-y = t*(n-m) + k*L

那麼,我們假設

    A = n-m, B = L, C = x-y,X = t, Y = k;

因此不就得到了這樣一個式子

    AX + BY = C                     ⑤

這跟上面提到的①式只是差了 C 和 gcd;因此,如果 C%gcd==0 ,那麼,這個方程就
有解,因為只需把①式的解 *(C/gcd) 就可以得到

    x=x0*(C/gcd) + d/a*t
    y=y0*(C/gcd) + d/b*t
    //至於後面為什麼不乘上(C/gcd) ,好好想下就明白了

相反,如果C%gcd!=0 ,就
意味著這個方程無解,而問題的最後是最小t也就是最小的正整數X,因此需要對X進行
一番處理

AC程式碼

#include<cstdio>
#include<iostream>
using namespace std;
typedef
long long ll; ll X, Y; ll exgcd(ll a, ll b) { if(b==0) { X = 1; Y = 0; return a; } ll r = exgcd(b ,a%b); ll t = X; X = Y; Y = t - a/b*X; return r; } int main() { int x, y, m, n, l; cin>>x>>y>>m>>n>>l; ll A = n-m, C = x-y, B = l; ll g = exgcd(A,B); ll D = A*B/g; //題目中明確了x != y,因此m == n 方程無解 if(m==n||C%g!=0) puts("Impossible"); else {//X是AX+BY=g方程的一個特解,%(D/A)將其的絕對值化為最小 //乘上(C/g)化為AX+BY=C的特解 ll t = X%(D/A)*(C/g)%(D/A); //t可能是負數,須將其化成最小正整數 if(t < 0) t += (D/A); cout<<t<<endl; } return 0; }