1. 程式人生 > >Flip and Shift -- ACM PKU 1063 解題報告

Flip and Shift -- ACM PKU 1063 解題報告

問題描述:This puzzle consists of a random sequence of m black disks and n white disks on an oval-shaped track, with a turnstile capable of flipping (i.e., reversing) three consecutive disks or shifting one position clockwise for each of the disks on the track. The goal of this puzzle is to gather the disks of the same color in adjacent positions using flips and shifts. You are to write a program which decides whether a given sequence can reach a goal or not. If a goal is reachable, then write a message "YES"; otherwise, write a message "NO".

詳見:http://acm.pku.edu.cn/JudgeOnline/problem?id=1063

我試著自己翻譯一下題意(意譯式的):在日本有一種旋轉壽司店,廚師把做好的壽司放到一個環形道上,而環形道在直在旋轉,這樣,圍著環形道坐的顧客就能品味到不同的壽司。現在,假設在一個 L 個單位長的環形道上,每個單位長度放著一個或黑或白的盤子。環形道本身並不自己旋轉,而是要靠一個機關來操作。這個機關固定在某個位置。它可以把它前面的三個連續的盤子反轉位置,或者把環形道順時針移動一個單位距離。例如,如果當前序列為 1 2 3 ... L,其中數字為盤子編號,而假定機關就在 3 號位置上,如果機關使用反轉功能,則序列變成 1 4 3 2

5 ... L (注意黑體部分);如果使用了移動功能,則序列變成 L 1 2 3 4 ... L-1 ,現在擺在機關面前的是 2 號盤子。這裡給盤子編號,是為了說明和舉例,原題描述中並無編號。現在的問題是,給了一個盤子序列,要通過操作機關來把所有黑盤調整到一塊,而所有白盤也在一塊。但不是所有序列都能這麼黑白兩分的,比如序列 黑白黑白 就不能兩分。寫一個程式,接受一個盤子序列為輸入,確定該序列是否可以黑白兩分。

看問題要看本質。讓我們先看看這個 turnstitle 到底能“真正”做些什麼。連續的三個盤子,可能的情況是:1) ooo 2) xox 3)oxx 4)xxo 其中, x 和 o 表示不同顏色的盤子。除此之後,沒有其它可能了。對於前兩種情況,使用了 turnstitle 的 flip 功能和沒使用是一樣的,因此不起作用。那麼,真正有用的就是後兩者情況了。扳動了 turnstitle 的 flip 功能, 就把 3)變成 4),或者把 4) 變成 3)。本質上,就是把連續的兩個 xx 向逆時針或順時針方向前進一格,同時把在它們正前面的 o 拋到後面去。比如 3),本質上就 xx 向左(逆時針)移動了一格,然後把它們前面,即 xx 左邊的那個 o 挪到 xx 的右邊。而 4)的情況正好是左右互換。再結合 shift 功能,我們就可以把連續的兩個 xx 向左或向右移動任意數量的格子!

基於以上本質上的觀察,要把黑的和白的分開,那麼,我們從 track 的任一處開始,把所有連續的兩個 xx 移動到一起,如果最後的結果是 xxx... ooo... 則成功了,否則,序列不可以被黑白兩分。例如 oxoxox 這些型別的序列,就不能黑白兩分的。事實上,可以發展一些嚴格的數學定義來說明,只有這一型別的序列不能黑白兩分,其它不能兩分的都能轉成這種型別的(同構)。簡單地說,就是對於 xx,我們可以把它們從序列中刪掉,而不影響序列的可分性。刪除這些 xx 之後,序列要麼為空,要麼為 o,要麼 ox,要麼為 oxox...ox。前兩者即為可分,後者顯然不可分。當我們寫程式時,實際碰到的還有另一種情況,即 oxox...oxo (長度為奇數,且 o 和 x 交替著出現)。事實上,它就是 o,因為 track 是環狀的,它可以通過繼續刪除 xx 這種組合,從而最後變成 o 型別。

這樣,我們只需要從頭開始掃描一遍序列,如果當前的盤子和前一個盤子顏色相同,則刪除掉當前盤子和前一個盤子,否則,當前的序列長度增加 1。當序列掃描結束時,如果序列的長度不大於 2 或長度為奇數,則可分,否則,不可分。

程式不長,我就打破我的慣例,貼一下我寫的C程式碼吧。我一般不貼程式碼,一覺得沒必要,二是覺得自己的程式碼很難看,不想貽笑於大方。

其中,T 為測試用例的數量,mn為序列長度, c 為當前已讀序列並結合了刪除操作的序列長度,dish 是當前盤子的顏色,top 是前一個盤子的顏色。