博弈論題目集 (持續更新)

2021-10-07 14:58:18 字數 4318 閱讀 1819

巴什博弈

hdu 1846

1、  本遊戲是乙個二人遊戲;

2、  有一堆石子一共有n個;

3、  兩人輪流進行;

4、  每走一步可以取走1…m個石子;

5、  最先取光石子的一方為勝;

這個應該比較好推:

如果 n % (m+1)==0 後手勝利 否則 先手勝利

#include#include#includeusing namespace std;

int main()

return 0;

}

斐波拉契博弈

hdu 2516

有一堆個數為n(n>=2)的石子,遊戲雙方輪流取石子,規則如下:

1、先手不能在第一次把所有的石子取完,至少取1顆;

2、之後每次可以取的石子數至少為1,至多為對手剛取的石子數的2倍;

3、約定取走最後乙個石子的人為贏家;

f[1]=1,f[2]=2的斐波那契數列

如果n為斐波拉契數列的一項,那麼先手必敗,否則先手必勝。

有篇解釋的很清楚的部落格:

#include#include#includeusing namespace std;

typedef long long ll;

ll f[50];

int main()

} if(flag) puts("second win");

else puts("first win");

} return 0;

}

hdu 1564 稍加一些思維的博弈

乙個n*n矩陣,一開始從左下角(任何乙個角落)開始走  不能走走過的格仔  問先手勝利還是後手勝利

我們畫出n*n的矩陣  並且講它進行分解

如果n為偶數  我們可以把它分解成很多個1*2的方塊  先手每次走到包含當前格仔的另外乙個方塊上就行  此時先手必勝

如果n為奇數  我們把起始點拿出來  剩下的格仔也能分成很多 1*2的方塊 此時先手每次走入乙個新的方塊 而後手走到這個方塊的另乙個格仔就行 此時後手必勝

#include#include#includeusing namespace std;

int main()else

} return 0;

}

hdu 1525

有兩個玩家,stan 和 ollie, 在玩遊戲。初始有兩個自然數。stan是先手,每次把大的數字減去小的數字的任意倍數,但是不能使數字變成負數。然後ollie進行同樣的操作,直到有乙個玩家使乙個數字變為零。

例如,初始時數字為(25,7):

25 7

11 7

4 74 3

1 31 0

這樣stan贏

要掌握一種思維 如果我走一步可以讓下乙個人達到必敗態 那我肯定是能贏的 這是顯然易見的

假設a>b 當a%b==0  顯然是當前操作的人勝利

當a>=2*b 也是當前操作的人勝利 為什麼呢   我們可以看 a%b,b的狀態是必敗態還是必勝態  如果是必敗態 那麼我就走到這個狀態 讓下乙個操作的人輸 否則我就走到 a%b+b,b這個狀態(是必敗的 因為它只能走到乙個必勝態a%b,b)

當a>b&&a<2*b時 進行一次簡單的操作(a=a%b,b=b) 然後更換一下當前操作的人就行了

#include#include#includeusing namespace std;

int main()

return 0;

}

nim博弈 hdu - 1850

nim博弈是比較經典的博弈:桌子上有m堆撲克牌;每堆牌的數量分別為ai (i=1…m);兩人輪流進行;每走一步可以任意選擇一堆並取走其中的任意張牌;桌子上的撲克全部取光,則遊戲結束;最後一次取牌的人為勝者。

先手必勝當且僅當 a[1]^a[2]^a[3]....^a[m] != 0

我們可以這樣推導  

假設 a[1]^a[2]^a[3]....^a[m] = x, 那麼肯定存在乙個牌堆 它的牌數目為a[i]  並且a[i]^x因此我們可以在 i 牌堆裡面取適當數目的牌 使得 a[i]->a[i]^x

到另外乙個人取牌的時候  a[1]^a[2]^a[3]....^a[m] = 0, 根據異或的性質 無論他怎麼取 取完以後  a[1]^a[2]^a[3]....^a[m] != 0

由數學歸納法可知: a[1]^a[2]^a[3]....^a[m] != 0 為必勝局面,一定存在一種行動讓對手面臨 「各堆牌異或起來等於0」 。 a[1]^a[2]^a[3]....^a[m] = 0 為必敗局面,無論如何行動,都會讓對手面臨乙個「各堆石子異或起來不等於0」 的必勝局面。

在來看這題  第一步能走的方案數  那肯定是 現求出 x  在遍歷a陣列  如果 a[i]>a[i]^x 則方案數+1

#includeusing namespace std;

int a[102];

int main()+1)/2" class="mathcode" src=""/>

#include#include#includeusing namespace std;

int main()

return 0;

}

映象原理 hdu - 3951 

映象原理:博弈論常用小技巧,當對方先操作時,我們可以模仿對方的操作來進行映象的操作以達到必勝的目的  

首先看乙個簡單的題  乙個長度為n的序列(首尾不相連) a,b兩人輪流進行操作  每次可以取連續的k(k<=n) 個數  最後取完的人勝利  (ps:如果第3個數被取了 那麼2和4不能同時取) 

顯然 如果 k==1  我們可以通過n的奇偶性判斷輸贏  如果n&1先手勝利 否則後手勝利

接下來就是映象原理的應用了:

k>=2的時候  先手可以從序列 居中的位置 取1個或2個連續的數 使得序列的左右兩端長度相同   進行完這個操作後 無論後手怎麼取 先手在對應的映象中取就行了 這樣先手是必勝的

hdu - 3951  這題把序列首尾相連變成了環形  當先手取完一次以後就變成序列了  然後再按上述方法 後手可以必勝 另外注意判斷一下特殊情況就行

#includeusing namespace std;

int main()

if(k==1&&n%2)

puts("second");

} return 0;

}

階梯博弈變形 hdu - 3389

普通的階梯博弈: 有n階從左往右遞增的樓梯  每一階上有一定數量的石子(可以為0) 0是最低階  兩個人輪流操作  每次操作可以選乙個階梯 取》0顆石子 往下放(放到左邊的下一階上) 最先不能操作的人輸 

看成奇數號階梯的nim博弈:我們這樣思考  當我把石子從奇數號階梯拿到偶數號階梯時 可以看做nim博弈的取石子操作 如果後手把偶數號階梯的石子放到了奇數號階梯  那先手只要把這些石子在放回偶數號階梯就行  仍然可以保證奇數號階梯的nim博弈

再來看這道題 題意可以轉化一下: b#include#includeusing namespace std;

int main()

printf("case %d: ",++ca);

if(xo) puts("alice");

else puts("bob");

} return 0;

}

簡單sg函式 hdu - 3032 

在nim博弈的基礎上增加了乙個分石子的操作   但是因為石子數目較大  無法直接打sg表   乙個常用的方法就是打一小部分的sg表 然後觀察規律即可 於是我打出了石子數小於等於100的sg表 經過觀察得知 

x%4==1||x%4==2 return x

x%4==3 return x+1

x%4==0 return x-1

#includeusing namespace std;

int vis[105],sg[105];

void init()

} for(int i = 0; i <= 100; i++) printf("sg[%d]=%d\n",i,sg[i]);

}int getsg(int x)

int main()

return 0;

}

博弈論題目整理

hdu 1079 暴力pn打錶能過或不太好找的規律 打表比較麻煩 hdu 1525 分析規律 暴力pn打表無法獲得直觀規律,pn打表提交炸時空 hdu 1564 超簡單的規律 無法pn 超水 hdu 1846 巴什模板 超水 hdu 1847 pn找規律 也可直接打表提交 水 hdu 2516 斐波...

簡單博弈論題目總結

bashgame i 有一堆石子共有n個。a b兩個人輪流拿,a先拿。每次最少拿1顆,最多拿k顆,拿到最後1顆石子的人獲勝。假設a b都非常聰明,拿石子的過程中不會出現失誤。給出n和k,問最後誰能贏得比賽。例如n 3,k 2。無論a如何拿,b都可以拿到最後1顆石子。include include u...

博弈論 入門,持續更新

本篇只對尼姆博弈和巴什博弈進行介紹 其餘博弈遇到了再加進去 定義 博弈論,又稱為對策論 game theory 賽局理論等,既是現代數學的乙個新分 支,也是運籌學的乙個重要學科。博弈論 是二人在平等的對局中各自利用對方的策略變換自己的 對抗策略,達到取勝的目的。巴什博弈 只有一堆n個物品,兩個人輪流...