有兩堆石子,數量任意,可以不同。遊戲開始由兩個人輪流取石子。遊戲規定,每次有兩種不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在兩堆中同時取走相同數量的石子。最後把石子全部取完者為勝者。現在給出初始的兩堆石子的數目,如果輪到你先取,假設雙方都採取最好的策略,問最後你是勝者還是敗者。
所謂威佐夫博弈,是acm題中常見的組合遊戲中的一種,大致上是這樣的:
有兩堆石子,不妨先認為一堆有 10,另一堆有 15 個,雙方輪流取走一些石子,合法的取法有如下兩種:
1、在一堆石子中取走任意多顆;
2、在兩堆石子中取走相同多的任意顆;
約定取走最後一顆石子的人為贏家,求必勝策略。
兩堆石頭地位是一樣的,我們用餘下的石子數(a,b)來表示狀態,並畫在平面直角座標系上。
和前面類似,(0,0)肯定是 p 態,又叫必敗態。(0,k),(k,0),(k,k)系列的節點肯定不是 p 態,而是必勝態,你面對這樣的局面一定會勝,只要按照規則取一次就可以了。再看 y = x 上方未被劃去的格點,(1,2)是 p 態。k > 2 時,(1,k)不是 p 態,比如你要是面對(1,3)的局面,你是有可能贏的。同理,(k,2),(1 + k, 2 + k)也不是 p 態,劃去這些點以及它們的對稱點,然後再找出 y = x 上方剩餘的點,你會發現(3,5)是乙個 p 態,如此下去,如果我們只找出 a ≤ b 的 p 態,則它們是(0,0),(1,2),(3,5),(4,7),(6,10)……它們有什麼規律嗎?
忽略(0,0),很快會發現對於第 i 個 p 態的 a,a = i * (sqrt(5) + 1)/2 然後取整;而 b = a + i。居然和**分割點扯上了關係。
前幾個必敗點如下:(0,0),(1,2),(3,5),(4,7),(6,10),(8,13)……可以發現,對於第k個必敗點(m(k),n(k))來說,m(k)是前面沒有出現過的最小自然數,n(k)=m(k)+k。
判斷乙個點是不是必敗點的公式與**分割有關(我無法給出嚴格的數學證明,誰能給出嚴格的數學證明記得告訴我),為:
m(k) = k * (1 + sqrt(5))/2
n(k) = m(k) + k;
#include#include#include
#include
using
namespace
std;
inta,b;
intmain()
int k=a-b;
a=(int)(k*(1+sqrt(5))/2.0
);
if(a==b)
printf(
"0\n");
else
printf(
"1\n");
}return0;
}
原來這tm是程式設計之美上的題。。。上面的結論程式設計之美上有證明。。。p72
還有一種找規律的方法。。。用類似質素的選擇的方法,過濾數的方法(2的倍數,3的倍數...),把必勝態都過濾掉。。。
然後剩下必敗態,(1,2),(3,5),(4,7)...比如(3,5)能被對方換為(1,2)。。。所以這樣下去就行。。。o(n)
取石子遊戲 (威佐夫博弈)
有兩堆石子,數量任意,可以不同。遊戲開始由兩個人輪流取石子。遊戲規定,每次有兩種不同的取法,一是可以在任意的一堆中取走任意多的石子 二是可以在兩堆中同時取走相同數量的石子。最後把石子全部取完者為勝者。現在給出初始的兩堆石子的數目,如果輪到你先取,假設雙方都採取最好的策略,問最後你是勝者還是敗者。in...
取石子遊戲(威佐夫博弈)
題目描述 有兩堆石子,數量任意,可以不同。遊戲開始由兩個人輪流取石子。遊戲規定,每次有兩種不同的取法,一是可以在任意的一堆中取走任意多的石子 二是可以在兩堆中同時取走相同數量的石子。最後把石子全部取完者為勝者。現在給出初始的兩堆石子的數目,如果輪到你先取,假設雙方都採取最好的策略,問最後你是勝者還是...
取石子(四)威佐夫博弈
有兩堆石子,數量任意,可以不同。遊戲開始由兩個人輪流取石子。遊戲規定,每次有兩種不同的取法,一是可以在任意的一堆中取走任意多的石子 二是可以在兩堆中同時取走相同數量的石子。最後把石子全部取完者為勝者。現在給出初始的兩堆石子的數目,如果輪到你先取,假設雙方都採取最好的策略,問最後你是勝者還是敗者。輸入...