題目來源:http://poj.org/problem?id=1061html
題目大意:ios
兩隻青蛙在網上相識了,它們聊得很開心,因而以爲頗有必要見一面。它們很高興地發現它們住在同一條緯度線上,因而它們約定各自朝西跳,直到碰面爲止。但是它們出發以前忘記了一件很重要的事情,既沒有問清楚對方的特徵,也沒有約定見面的具體位置。不過青蛙們都是很樂觀的,它們以爲只要一直朝着某個方向跳下去,總能碰到對方的。可是除非這兩隻青蛙在同一時間跳到同一點上,否則是永遠都不可能碰面的。爲了幫助這兩隻樂觀的青蛙,你被要求寫一個程序來判斷這兩隻青蛙是否可以碰面,會在何時碰面。
咱們把這兩隻青蛙分別叫作青蛙A和青蛙B,而且規定緯度線上東經0度處爲原點,由東往西爲正方向,單位長度1米,這樣咱們就獲得了一條首尾相接的數軸。設青蛙A的出發點座標是x,青蛙B的出發點座標是y。青蛙A一次能跳m米,青蛙B一次能跳n米,兩隻青蛙跳一次所花費的時間相同。緯度線總長L米。如今要你求出它們跳了幾回之後纔會碰面。 算法
輸入:輸入只包括一行5個整數x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。ide
輸出:輸出碰面所須要的跳躍次數,若是永遠不可能碰面則輸出一行"Impossible"spa
Sample Inputcode
1 2 3 4 5
Sample Outputhtm
4
終於有一道中文題目了,真是淚流滿面T^T..blog
由題意知,實際上問題是要求解下面的方程: ci
(1)get
其中 t 爲未知數,要求的是 t 的非負最小值。上式可變形爲: (2)
其中 t 和 k 爲未知數。再將上式簡化爲(3) 的形式。其中, a b c 均爲整數常數。數論中的相關理論(具體什麼理論我也不知道=。=)保證了:當 c = gcd(a, b)時,該方程的 t 和 k 必定有解。因此若是能夠把(2)式轉化爲 (4) 的形式,則原問題有解,不然無解,應輸出「Impossible.」。
接下來講明(4)式的解法--擴展的歐幾里得算法。
首先請移步這裏回顧一下求兩數最大公約數的樸素歐幾里得算法。而後, 咱們把代碼搬過來:
int gcd(int a, int b) { if(b == 0) return a; return gcd(b, a % b); }
所謂的擴展歐幾里得算法,代碼以下:
int x, y;
int ex_gcd(int a, int b) { if (b == 0) { x = 1; y = 0; return a; } else { int r = ex_gcd(b, a % b); int t = x; x = y; y = t - a / b * y; return r; } }
這裏的a, b與前面方程(4)裏的a, b對應, x, y對應t, k,返回值爲gcd(a, b)。[ax + by = gcd(a, b)]. 咱們發現,ex_gcd算法與gcd相比,多了 x 與 y 的賦值過程。只要在紙上演算一下,會發現其實算法很好理解:
1. b == 0 時,對應方程 gcd(a, b) = a, 對應的原方程爲:ax + 0y = a, 因此能夠賦值 x = 1, y = 0;
2. 當 b != 0 時,由於gcd(a, b) = gcd(b, a % b). 因此存在x'和y'知足:
ax + by = gcd(a, b)
= gcd(b, a % b)
= bx' + (a % b)y'
= bx' + (a - a / b * b)y'
= ay' + b(x' - a / b * y')
因而咱們從上面連等式中能夠找到對應關係:x = y'; y = x' - a / b * y'. 算法就是利用該遞推關係就求出方程(4)的一組解,設之爲(x0, y0)。
顯然解不是惟一的,而是應該構成一組解系。設gcd(a, b) = d, 則 ax0 + by0 = d, 且有:
因而咱們構造出瞭解系: 其中n爲任意整數。
而後對於通常形式的方程 ax + by = c, 則對應着解系. 因此若是 c/gcd(a, b) 是整數,則該方程有整數解,若不是則無整數解。
那麼回到題目中,本題實際上求的是知足方程的x中的最小非負值,求得了x0和d後應該是不可貴到了。至此應該把原理講清楚了吧,嗯,上AC代碼。
1 //////////////////////////////////////////////////////////////// 2 // POJ1061 Frogs' Dating 3 // Memory: 216K Time: 0MS 4 // Language: C++ Result : Accepted 5 //////////////////////////////////////////////////////////////// 6 7 #include <iostream> 8 9 using namespace std; 10 11 long long x, y; 12 13 long long ex_gcd(long long a, long long b) { 14 if (b == 0) { 15 x = 1; 16 y = 0; 17 return a; 18 } else { 19 long long r = ex_gcd(b, a % b); 20 long long t = x; 21 x = y; 22 y = t - a / b * y; 23 return r; 24 } 25 } 26 27 int main(void) { 28 long long X, Y, m, n, L, c, d, t; 29 cin >> X >> Y >> m >> n >> L; 30 c = X - Y; 31 d = ex_gcd(n - m, L); 32 t = c % d; 33 if (t == 0) { 34 long long k = c / d; 35 x *= k; 36 t = d * x / L; 37 x -= t * L / d; 38 if (x < 0) { 39 x += L / d; 40 } 41 cout << x << endl; 42 } else { 43 cout << "Impossible" << endl; 44 } 45 return 0; 46 }
關於求知足條件的最小非負數的附加解釋:
令 ,此時求得的n對應着最接近0的x,若是算出的x小於0,則在它的基礎上再加一個週期 b/d 便可。