博弈論 ( 斐波那契博弈 )——取石子游戲 ( HDU 2516 )
阿新 • • 發佈:2019-02-16
分析:
遊戲規則:
① 先手不能一次取完所有石子
② 之和每次可以取得的石子數在1~上次對方取的石子數的兩倍之間(閉區間)
③先取完的獲勝題解:
通過數學歸納法找規律,得出必敗數。
過程:- 2塊石頭:先手敗
- 3塊石頭:先手敗
- 4塊石頭:先手贏(先取1,後者怎麼取,先手都能贏)
- 5塊石頭:先手敗(無法到達必勝點4)
- 6塊石頭:先手勝(先手拿一塊,使對方位於必敗點5)
- 7塊石頭:先手勝(理由同上,注意,如果雙倍先手拿的能拿完整個石堆就不行了)
- 8塊石頭:先手敗(先手拿三塊及以上就直接輸了,拿1或2塊則使對方處於必勝點)
- 9塊石頭:先手勝(直接使對方位於必敗8)
- 10塊石頭:先手勝(同上)
- 11塊石頭:先手勝(同上)
- 12塊石頭:先手勝(不能直接拿4塊,否則對方會拿完,所以分步來,先拿1塊使得對方位於必敗3:對方只能拿1或者2,然後再補刀到必敗8;或者可以計算差值,12到最近的必敗點8差4,4是必勝點,所以12也是必勝點)
- 13塊石頭:先手敗(照上面的做法,13到最近的必敗點8差5,但5是必敗點,所以13必敗)
- …
- 推出結論
- 2,3,5,8,13為必敗點,根據找最近必敗點的規律,我們可以發現若不能直接使得對方陷入必敗點的話,就需要開始計算與最近必敗點的差值來判斷,如此推算,我們可以得出每個必敗點剛好是前兩個必敗點的和,即斐波那契數。
AC程式碼:
#include <iostream>
#include <cstdio>
#include <cstdio>
#include <map>
using namespace std;
typedef long long LL;
LL Fib[222];
map<LL,int> Q;
void init()
{
Fib[0] = 0;
Fib[1] = 1;
Q[0] = 1;
Q[1] = 1;
for(int i=2;i<=100;i++)
{
Fib[i] = Fib[i-1] + Fib[i-2];
Q[Fib[i]] = 1 ;
}
}
LL n;
int main()
{
init();
while(~scanf("%lld", &n)&&n)
{
if(Q.count(n) == 1)
cout << "Second win\n";
else
cout << "First win\n";
}
return 0;
}