1. 程式人生 > >bzoj1022: [SHOI2008]小約翰的遊戲John(博弈SG-nim遊戲)

bzoj1022: [SHOI2008]小約翰的遊戲John(博弈SG-nim遊戲)

mat flag enter int ans problem blank 入門題 pos

1022: [SHOI2008]小約翰的遊戲John

題目:傳送門

題目大意:

   一道反nim遊戲,即給出n堆石子,每次可以取完任意一堆或一堆中的若幹個(至少取1),最後一個取的LOSE

題解:

   一道很不錯的題目啊,感覺可以作為一道很好的入門題

   讀前一戳:博弈論文 && POPQQQ大佬%%%

   大體要分為三種情況來討論:

   1、全是為1的石子堆,如有偶數堆則先手勝,反之後手勝

   2、有兩堆相同的石子且都不為1(後手獲勝的幾率很大):
       那麽如果先手將其中一堆取剩1,那麽後手就可以將另一堆取完,此時後手勝

       如果先手將其中一堆取完,那麽後手就可以將另一堆取剩1,還是後手勝

   如果先手僅拿走其中一堆的一部分,那麽後手可以進行相同的操作,將另一堆也拿走相同的數量(這是情況又回到了上面兩種)

   3、如果異或和不為0,那麽對於一般的nim遊戲一定可以將石子堆變成僅剩兩堆相同的(平衡狀態xor=0),這時又如上面所述了

  總結:

   如果全是石子數為1,異或和為0則先手勝,反之後手勝

   如果有不為1的,異或和不為0則先手勝,反之後手勝

代碼:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cmath>
 5
#include<algorithm> 6 using namespace std; 7 int T,n; 8 int main() 9 { 10 scanf("%d",&T); 11 while(T--) 12 { 13 scanf("%d",&n);int x,ans=0;bool flag=true; 14 for(int i=1;i<=n;i++) 15 { 16 scanf("%d",&x);ans^=x; 17 if
(x!=1)flag=false; 18 } 19 if(flag==true) 20 { 21 if(ans==0)printf("John\n"); 22 else printf("Brother\n"); 23 } 24 else 25 { 26 if(ans==0)printf("Brother\n"); 27 else printf("John\n"); 28 } 29 } 30 return 0; 31 }

bzoj1022: [SHOI2008]小約翰的遊戲John(博弈SG-nim遊戲)