1. 程式人生 > >博弈論 ( 斐波那契博弈 )——取石子游戲 ( HDU 2516 )

博弈論 ( 斐波那契博弈 )——取石子游戲 ( HDU 2516 )

  • 分析:
    遊戲規則:
    ① 先手不能一次取完所有石子
    ② 之和每次可以取得的石子數在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; }