POJ 1061 :拓展歐幾里德
阿新 • • 發佈:2019-02-06
題目為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進行
一番處理
#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;
}