切換
舊版
前往
大廳
主題

ZeroJudge - b588: 撿石頭遊戲 解題心得

Not In My Back Yard | 2020-08-23 00:00:04 | 巴幣 0 | 人氣 878

題目連結:


題目大意:
輸入有多列,每列給定三整數 x 、 y 、 z (1 ≦ x ≦ 100 , 0 ≦ y 、 z ≦ 100 ,當輸入只有一個「0」時,代表輸入結束),代表有三堆石頭,分別有著 x 、 y 、 z 顆石頭。

現在有兩個人 Arthur 和 Caroll 要玩遊戲(假設兩人都以最佳策略遊玩,且 Arthur 為先手),規則如下:
兩個人輪流拿石頭;
可以選定從其中的一堆、任兩堆或是三堆,拿走相同數目的石頭;
輪到該人但沒有石頭可以拿的時候,該名玩家就輸了。

如果 Arthur 必贏,輸出「w」;反之,輸出「l」。



範例輸入:
1 1 1
1 2 0
0


範例輸出:
w
l


解題思維:
先觀察只有兩堆石頭時的情況:
從上可以看到圖中有出現「L」(代表先手必輸,用大寫是因為避免 L 與其他字母數字混淆,但是記得題目要求是小寫的「l」)的直線往右、直線往下以及往右下的對角線路途上皆為「W」(代表先手必勝),如下圖的紅線所示:
會這樣是因為,在圖中直直地往左代表從 y 那一堆移除石頭、直直向上代表從 x 那一堆移除,而往左上對角線移動則是同時從 x 、 y 兩堆移除等量的石頭。

因為那些被紅線覆蓋到的「W」可以藉由「一次」的移除石頭達到先手必輸「L」的局面。因為先手動了「一次」,所以原先的後手變成了「先手」(只單看移除石頭後的局面的話)、原先的先手變成了「後手」。而因為「現在」是先手必輸,即後手必贏,因此原本的先手必贏。

同樣地,那些是先手必輸「L」的局面是因為無法藉由一次的移除石頭達到另一個先手必輸的局面,即圖中往左、往上以及往左上方向找到一個「L」。



所以回到三堆版本也是同上,只是二維有三個直線方向(往左、往上、往左上)要考慮,現在則是有七個方向:
已知 (i, j, k) 是一個先手必輸之局面,即「L」,則
(i + n, j, k)
(i, j + n, k)
(i, j, k + n)
(i + n, j + n, k)
(i + n, j, k + n)
(i, j + n, k + n)
(i + n, j + n, k + n)
的局面皆是先手必勝,即「W」。 其中 n 為任意正整數。

而已知 (0, 0, 0) 是「L」,接著由此延伸求得其他情況即可,典型的動態規劃(Dynamic Programming,DP)之精神。



不過不一定要按照上面的七種可能局面去窮舉合理的 n 值(不會超出所求範圍的),可以將其簡化。

再次回到二維的版本,觀察紅線:
可以看到與「L」同一列(這邊是只單指「L」的右邊,因為左邊的「W」不是從這個「L」得來)、同一行(單指「L」下面)的都是「W」,所以可以化簡為兩個布林陣列,一個看某一列 r 有無「L」、另一個則是看某一行 c 有無「L」。

那剩下那一條對角線呢?同樣也可以將座標化為一個值,即列座標 - 行座標(同一條對角線上的點都會是同一個值),因此也可以用一布林陣列表示。

而上述的方法可以類推到三維,但是從原本的三條線變為現有的七條線。而三維空間中要表示一條「線」需要兩個「平面」,而一個平面的通式為 aX + bY + cZ = d,所以會需要兩個這樣子(而且要彼此線性獨立)的關係式表達。因此會出現兩個獨立的 d 值 d1 、 d2 。

例如已知 (x, y, z) 是「L」,其中
(x, y + n, z + n)
這條線可以用 X = x 和 Y - Z = y - z 這兩個平面表示;
(x + n, y, z)
這條線可以寫為 Y = y 和 Z = z 二式云云。任意一條線可以有無限多種寫法。

所以原本二維的布林陣列只有一個維度,現在的則需要兩個維度(當然,要壓成一個維度也是可以的)。




此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。

創作回應

更多創作