一年在外 父母時刻牽掛
春節回家 你能做幾天好孩子嗎
寒假裏嘗試做做下面的事情吧
陪媽媽逛一次菜場
悄悄給爸爸買個小禮物
主動地 強烈地 要求洗一次碗
某一天早起 給爸媽用心地做回早餐
如果願意 你還可以和爸媽說
咱們玩個小遊戲吧 ACM課上學的呢~
下面是一個二人小遊戲:桌子上有M堆撲克牌;每堆牌的數量分別爲Ni(i=1…M);兩人輪流進行;每走一步可以任意選擇一堆並取走其中的任意張牌;桌子上的撲克全部取光,則遊戲結束;最後一次取牌的人爲勝者。
現在我們不想研究到底先手爲勝還是爲負,我只想問大家:
——“先手的人如果想贏,第一步有幾種選擇呢?”Input
輸入數據包含多個測試用例,每個測試用例佔2行,首先一行包含一個整數M(1<M<=100),表示撲克牌的堆數,緊接着一行包含M個整數Ni(1<=Ni<=1000000,i=1…M),分別表示M堆撲克的數量。M爲0則表示輸入數據的結束。
Output
如果先手的人能贏,請輸出他第一步可行的方案數,否則請輸出0,每個實例的輸出佔一行。
Sample Input
3 5 7 9 0
Sample Output
1
思路:一個基礎的Nim博弈,首先我們要知道一個東西就是a1^a2^a3....an=0的話那麼先手必敗,
若a1^a2^...^an!=0,一定存在某個合法的移動,將ai改變成ai'後滿足a1^a2^...^ai'^...^an=0。若a1^a2^...^an=k,則一定存在某個ai,它的二進制 表示在k的最高位上是1(否則k的最高位那個1是怎麼得到的)。這時ai^k<ai一定成立。則我們可以將ai改變成ai'=ai^k,那麼最後^起來還是爲0
#include<iostream>
#include<cstdio>
using namespace std;
const int N=105;
int a[N];
int main(){
int n,temp=0,cnt;
while(cin>>n&&n){
cnt=0;
temp=0;
for(int i=0;i<n;i++){
cin>>a[i];
temp^=a[i];
}
for(int i=0;i<n;i++){
int t=a[i]^temp;
if(a[i]>t) cnt++;//該堆石子在二進制的最高位上
}
cout<<cnt<<endl;
}
return 0;
}
常見博弈總結:
1.Nim博弈
n堆石子,兩人輪流取,只能在一堆中取,規定每次至少取一個,最多取一堆,最後取完者獲勝
用0與每個數異或,如最後結果爲0,則後手勝
- 設一數組a[m],令sum=0
- 循環與數組每一個數據異或(sum^=a[i])
- sum最後等於0則後手勝
0異或各堆物品,結果爲零————後手勝
//a[m]每堆物品的數量 sum=0
int Nimm_Game(int m)
{
for(int i=0;i<m;i++)
sum = sum ^ a[i];
if(sum == 0)
return 0;
return 1;
}
2.巴什博弈
只有一堆n個物品,兩個人A,B輪流從這堆物品中取物,規定每次至少取一個,最多取m個,取最後一個物品的人得勝
分析:
- 當 n = m + 1 時,第一個人不可能獲勝;
- 當 n = k*(m + 1) + r 時,先取者拿走 r 個,那麼後者再拿(1~m)個 , 此時 n =(k-1)*(m+1)+s先取者再拿走s 個 最後總能造成 剩下n=m+1 的局面
- 若n=k*(m+1) 那麼先取者必輸
int Bash_Game(int n,int m)
{
if (n%(m+1)==0) //後手勝
return 0;
return 1;
}
3.威佐夫博弈
兩堆各有若干個物品,兩人輪流從某一堆中任意取或者同時從兩堆中取同樣多的物品,最後取光着勝
- 兩堆石子的狀態爲 [ak,bk] (滿足ak<=bk)
- 當 ak=(k*(√5+1)/2), bk=ak+k 時滿足奇異局勢,那麼則先手輸,反之則先手贏
若(大-小)*(1+sqrt(5))/2==小————後手勝
t=(max(n,m)-min(n,m))*(1+sqrt(5))/2;
if(t==min(n,m)) 後手勝
else 先手勝
int Wythoff_Game(int a,int b)
{
double x=(1+sqrt(5))/2;
int n=b-a;
if(a==(int)(x*n))
return 1;
return 0;
}
4.環形博弈
n個石子圍成一個環,每次取一個或者取相鄰的兩個,取完最後石子的人勝
if 石子數<=2 先手勝
else 先手輸(消滅不對稱因素後對稱取石子)
5.斐波那契博弈
一堆石子n個
- 先手不能在第一次把所有的石子取完,至少取一顆
- 之後每次可以取得石子數至少爲1,至多爲對手取得石子數的2倍
- 約定取走最後一個石子的人爲贏家
結論:若n爲斐波那契數列,則後手勝
參考博客:https://blog.csdn.net/qq_40907279/article/details/83718880