Nim博弈
忽然發現博弈論是個很好玩的東西哎
之前假期學長講課的時候就發現這種必勝的戰略可以用來坑人做題
這兩天終于做了第一道博弈論的題,寫篇博客紀念一下
靈感來源:洛谷P1247
Pre-scene
眾所周知,李明和Jenny都喜歡Danny,為了爭奪Danny的所有權,他們決定玩一個游戲。規則是這樣的:
有k堆撲克牌(不成套),兩人輪流從某一堆中拿出x張牌,不能不拿,也不能跨堆拿牌,拿走最后一張(堆)牌的一方獲勝。
命運當然是不公平的,李明來向你請教有沒有必勝的方法,你聰明的,能告訴他么
?
0X10 ?知識
先來了解一下,什么是Nim博弈
?
通常的Nim游戲的定義是這樣的:有若干堆石子,每堆石子的數量都是有限的,合法的移動是“選擇一堆石子并拿走若干顆(不能不拿)”,如果輪到某個人時所有的石子堆都已經被拿空了,則判負(因為他此刻沒有任何合法的移動)。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ——百度百科?
?
了解Nim游戲之后,我們會發現這是一個經典的ICG游戲(不要問我什么是ICG因為我百度百科也不知道)
顯然游戲有兩種局面,先手必敗和先手必勝,我們分別定義他們為P-position和N-position兩種,其中P代表Previous,N代表Next,那么我們可以得出,從N-position轉移而來的一定是P-position,反之也成立。
0X20 ?簡單的證明
我們先來手玩一組小數據,一共有2堆石子,每一堆都有3個,你是先手的話,會怎么拿?由規則我們知道,玩家的目標是拿走最后一個石子,所以先手的你一定不會把某一堆全部拿走,因為如果這樣,后手將會拿走另一堆,先手必敗;但是如果你先拿1個,后手會跟著你從另一堆也拿一個,你拿2個,后手仍可以做和你一樣的操作,先手必敗。至此我們發現,(3,3)是一個P-position的局面。
推論:1.當a1^a2^a3^……a^n=0時,為P-position,即先手必敗。
? ? ? ? ?2.當a1^a2^a3^……a^n!=0時,一定存在某個移動,使得局面變成一個P-position,即此局面為N-position。
0X30 ?實現
直接異或運算即可,代碼過于簡單就不放了。
0X40 ?題解
傳送門
了解了上述知識后,這道題幾乎就是一個裸的板子了,就是加了一個輸出怎么取和取完的狀態而已,這也很好實現。
0X41 ?怎么取
由于我們發現異或和不等于0,我們就要考慮怎么取使得其等于0了。
設k=a1^a2^a3^……a^n,因為k!=0,而顯然k^k=0,所以要使a1^a2^a3^……a(n-1)^an^k=0,只需要把其中一個ai變成ai^k即可,又因必須要取,可得ai^k<ai
0X42 ?取完的狀態
直接更改即可
0X43 ?代碼
1 // 2 // main.cpp 3 // Luogu 4 // 5 // Created by gengyf on 2019/5/16. 6 // Copyright ? 2019 yifan Geng. All rights reserved. 7 // 8 9 #include <cstdio> 10 int n; 11 int a[500005]; 12 int main(){ 13 scanf("%d",&n); 14 int check=0; 15 for(int i=1; i<=n; i++){ 16 scanf("%d",&a[i]); 17 check^=a[i]; 18 } 19 if(!check){ 20 printf("lose\n"); 21 return 0; 22 } 23 for(int i=1; i<=n; i++){ 24 if((check^a[i])<a[i]){ 25 printf("%d %d\n",a[i]-(check^a[i]),i); 26 for(int j=1; j<=n; j++) 27 if(j!=i) 28 printf("%d ",a[j]); 29 else printf("%d ",check^a[i]); 30 break; 31 } 32 } 33 return 0; 34 }?
轉載于:https://www.cnblogs.com/gengyf/p/10878126.html
總結
- 上一篇: asp.net中大文件下载
- 下一篇: 每天一点点之 taro 框架开发 - t