1. 程式人生 > >博弈專題(5種模板)

博弈專題(5種模板)

()巴什博弈(BAsh Game)

題目模板

  • 只有一堆n個物品
  • 兩個人輪流取,每次只能取1~m個物品,誰先取完,誰勝利;(n,m是輸入的隨機數)

解題思路

  1. n = m + 1 時 第一個取的人不可能獲勝;
  2. n = k*(m + 1) + r 時           (k,r,s都是未知的整數)

    先取者拿走 r 個,那麼後者再拿(1~m)個

    此時 n =(k-1)*(m+1)+s

    先取者再拿走s 個 最後總能造成 剩下n=k*(m+1) 的局面

    若n=k*(m+1) 那麼先取者必輸

  3. 若n=k*(m+1) 那麼先取者必輸

求解巴什博弈函式

int Bash_Game(int n,int m)//是否先手有必贏策略
{
    if (n%(m+1)!=0)
	    return 1;
    return 0;
}

樣題:HDU 2147 kiki's game            HDU 2149 Public Sale          HDU 1846 Brave Game       

HDU 2188 悼念512汶川大地震遇難同胞——選拔志願者

 

 

()威佐夫博奕(Wythoff's game)

題目模板

  • 有兩堆各若干個
  • 兩個人輪流從某堆或同時從兩堆取同樣多的物品
  • 規定每次至少取一個,多者不限,最後取光的人勝利

解題思路

  • 兩堆石子的狀態為 [a,b] (滿足a<=b)
  • 當 a=(k*(√5+1)/2), b=a+k 時滿足奇異局勢,那麼則先手輸,反之則先手贏

求解威佐夫博奕函式

int Wythoff_Game(int a,int b)//b要大於a
{
    double x=(1+sqrt(5))/2;
    int n=b-a;
    if(a==(int)(x*n))
        return 1;
    return 0;
}

樣題:HDU 1527 取石子游戲           HDU 2177 取(2堆)石子游戲

 

 

() 尼姆博奕(Nimm's Game)

題目模板

  • 有多堆各若干個物品,兩個人輪流從某一堆取任意多的物品,規定每次至少取一個,多者不限,最後取光者得勝。

​​​​​​​解題思路

  • 用0與每個數異或,如最後結果為0,則後手勝

  • 設一陣列a[n][m],令sum=0

  • 迴圈與陣列每一個數據異或(sum^=a[i][j])

  •  sum最後等於0則後手勝

​​​​​​​求解尼姆博弈函式

a[m]每堆物品的數量  sum=0

int Nimm_Game(int n,int m)//n堆物品,m個物品
{
    for(int i=0;i<n;i++)
	    for(int j=0;j<m;j++)
		    sum = sum ^ a[i][j];
	if(sum == 0)
		return 0;
	return 1;
}

樣題:HDU 1850 Being a Good Boy in Spring Festival

           HUD 1907 John        HDU 2509 Be the Winner

           HDU 1849 Rabbit and Grass

 

 

(四) 斐波那契博弈

題目模板

  • 有一堆個數為n的石子,遊戲雙方輪流取石子,
  • 滿足:
  • 先手不能在第一次把所有的石子取完;
  • 之後每次可以取的石子數介於1到對手剛取的石子數的2倍之間(包含1和對手剛取的石子數的2倍)

求解斐波那契博弈函式 f[50]

int Fib_Game(int n)
{
	f[1]=1;f[2]=1;
	for(int i=3;i<=50;i++)
		f[i] = f[i-1] + f[i-2];
	if( 陣列f 中包含 n )
		return 1;//先手贏
	return 0;
}

樣題:HDU 2516 取石子游戲

 

 

(五) 環形博弈

題目模板

  • n個石子圍成一個環,每次取一個或者取相鄰的2個(每個石子有序號)

​​​​​​​求解

  • 石子數<=2先手贏,否則後手贏