【BZOJ - 2144】跳跳棋
@跳跳棋@
- @跳跳棋@
- @題目描述@
- @分析1@
- @分析2@
- @代碼實(shí)現(xiàn)@
- @END~@
@題目描述@
Description
跳跳棋是在一條數(shù)軸上進(jìn)行的。棋子只能擺在整點(diǎn)上。每個(gè)點(diǎn)不能擺超過(guò)一個(gè)棋子。我們用跳跳棋來(lái)做一個(gè)簡(jiǎn)單的游戲:棋盤上有3顆棋子,分別在a,b,c這三個(gè)位置。我們要通過(guò)最少的跳動(dòng)把他們的位置移動(dòng)成x,y,z。(棋子是沒(méi)有區(qū)別的)跳動(dòng)的規(guī)則很簡(jiǎn)單,任意選一顆棋子,對(duì)一顆中軸棋子跳動(dòng)。跳動(dòng)后兩顆棋子距離不變。一次只允許跳過(guò)1顆棋子。
寫一個(gè)程序,首先判斷是否可以完成任務(wù)。如果可以,輸出最少需要的跳動(dòng)次數(shù)。
Input
第一行包含三個(gè)整數(shù),表示當(dāng)前棋子的位置a b c。(互不相同)
第二行包含三個(gè)整數(shù),表示目標(biāo)位置x y z。(互不相同)
Output
如果無(wú)解,輸出一行NO。如果可以到達(dá),第一行輸出YES,第二行輸出最少步數(shù)。
Sample Input
1 2 3
0 3 5
Sample Output
YES
2
【范圍】
100% 絕對(duì)值不超過(guò)10^9
@分析1@
這道題真的很跳……
首先這樣的題如果用絕對(duì)坐標(biāo)(a, b, c)來(lái)做絕對(duì)不好做,所以考慮使用相對(duì)距離來(lái)表示點(diǎn)。對(duì)于三元組(a, b, c)將它表示為(l, r, m) = (b-a, c-b, m),含義為:(左邊點(diǎn)離中間點(diǎn)的距離,右邊點(diǎn)離中間點(diǎn)的距離,中間點(diǎn)坐標(biāo))。
然后對(duì)于題目所提到的操作將操作拆為兩種:邊緣點(diǎn)往中間跳,中間點(diǎn)往兩邊跳。
當(dāng)r>l時(shí),左邊點(diǎn)可以往中間跳,從(l, r, m)轉(zhuǎn)移到了(l, r-l, m+l)
當(dāng)l>r時(shí),右邊點(diǎn)可以往中間跳,從(l, r, m)轉(zhuǎn)移到了(l-r, r, m-r)
中間點(diǎn)往兩邊跳沒(méi)有附加條件,從(l, r, m)可以轉(zhuǎn)移到(l, r+l, m-l)與(l+r, r, m+r)
這樣就可以建圖,問(wèn)題轉(zhuǎn)化為求圖上兩點(diǎn)最短距離。
但是……這還是不夠。考慮到中間往兩邊跳是兩邊往中間跳的逆操作,我們可以給邊定向,即只考慮兩邊往中間跳的操作。然后我們發(fā)現(xiàn),對(duì)于某一個(gè)狀態(tài)(l, r, m),通過(guò)兩邊往中間跳的操作后,l和r不會(huì)變得更大,所以這是一個(gè)有向無(wú)環(huán)圖。更進(jìn)一步地,當(dāng)l < r或l > r時(shí),狀態(tài)有唯一轉(zhuǎn)移,否則狀態(tài)無(wú)轉(zhuǎn)移。聯(lián)想到有根樹(shù)上除根節(jié)點(diǎn)外每個(gè)節(jié)點(diǎn)只有一個(gè)父親,根節(jié)點(diǎn)沒(méi)有父親。所以這其實(shí)是一顆樹(shù),且狀態(tài)(l, r-l, m+l)或(l-r, r, m-r)是狀態(tài)(l, r, m)的父節(jié)點(diǎn),當(dāng) l = r 時(shí)狀態(tài)(l, r, m)是根節(jié)點(diǎn)。
問(wèn)題轉(zhuǎn)化為求樹(shù)上兩點(diǎn)最短距離。
再簡(jiǎn)單轉(zhuǎn)化,就是求樹(shù)上兩點(diǎn)的LCA。
@分析2@
分析到這一步已經(jīng)很不容易,但是還還還不夠……
考慮到我們一般做LCA的方法:倍增法。先 O(log2n) O ( l o g 2 n ) 的時(shí)間將兩個(gè)點(diǎn)跳到相同深度,再一級(jí)一級(jí)地同時(shí)往上跳直到兩個(gè)點(diǎn)相同。但是倍增法我們需要 O(n) O ( n ) 的dfs預(yù)處理,所以此處并不適用。
再觀察一下這個(gè)轉(zhuǎn)移的定義:
當(dāng)r>l時(shí),左邊點(diǎn)可以往中間跳,從(l, r, m)轉(zhuǎn)移到了(l, r-l, m+l)
當(dāng)l>r時(shí),右邊點(diǎn)可以往中間跳,從(l, r, m)轉(zhuǎn)移到了(l-r, r, m-r)
再聯(lián)想一下gcd的減法形式gcd(x, y) = gcd(y, x-y) = gcd(x-y, y) ( x > y )
是不是有點(diǎn)像?對(duì)于某一個(gè)狀態(tài),假設(shè) l < r,則(l, r-l, m+l),(l, r-2l, m+2l),…,(l, r%l, m+r/l*l)都是狀態(tài)(l, r, m)的祖先。但是!與gcd算法不同的是,如果r%l=0的話則不能跳到最上面的節(jié)點(diǎn),因?yàn)樵谧詈蟮臅r(shí)候 l 將會(huì)等于 r。
因?yàn)間cd的復(fù)雜度可以證明得到不超過(guò) log(n) l o g ( n ) ,所以我們就有了一個(gè)代替倍增的玩意兒。
具體來(lái)說(shuō),我們先求出兩個(gè)點(diǎn)的深度,以及兩個(gè)點(diǎn)所在樹(shù)的根節(jié)點(diǎn)。比較根節(jié)點(diǎn)判斷是否有解。
【為了簡(jiǎn)稱,我們稱(l, r, m)到達(dá)(l, r%l, m+r/l*l)為“大步跳”】【作者太Lazy了233】
然后,對(duì)于深度較大的節(jié)點(diǎn),假如它通過(guò)“大步跳”到達(dá)的節(jié)點(diǎn)深度比另外一個(gè)節(jié)點(diǎn)大,則它就直接跳到深度相同的地方;否則就跳到“大步跳”到達(dá)的節(jié)點(diǎn),并繼續(xù)迭代。
再然后,取兩個(gè)點(diǎn)“大步跳”到達(dá)的點(diǎn)中深度較大的點(diǎn),假如說(shuō)在這個(gè)點(diǎn)之前它們就已經(jīng)相遇了,就直接跳到相遇的點(diǎn)作為它們兩個(gè)點(diǎn)的LCA;否則就同時(shí)往上跳到深度較大的點(diǎn)的深度,并繼續(xù)迭代。
@代碼實(shí)現(xiàn)@
非常丑陋……不建議參考。
如果還有什么不懂的地方就評(píng)論在下面吧,作者會(huì)盡力解疑的。
【這道題太毒瘤啦……建圖卡死人,LCA卡死人,竟然冒出來(lái)個(gè)gcd……】
@END~@
就是這樣,新的一天里,也請(qǐng)多多關(guān)照哦(ノω<。)ノ))☆.。~
總結(jié)
以上是生活随笔為你收集整理的【BZOJ - 2144】跳跳棋的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: it企业实习_大学生IT公司实习报告
- 下一篇: 如何对一个产品编写完整的用户故事?