Poj1704:staircase nim【博弈】
題目大意:有一個無限長的一維的棋盤,棋盤上N個格子放置著棋子。兩個人輪流操作,每次操作能選擇其中一個棋子向左移動,但不能越過其它棋子或者兩枚棋子放在同一格中,最后不能操作的人算輸,問先手是否必勝?
思路:就是裸的階梯博弈(staircase nim)方法也很簡單。首先每個棋子能向右移動的距離是有限的,最多到前一個棋子處就停止了,比如第一個sample :1 2 3 每個棋子都不能移動就是 0 0 0 第二個sample: 1 5 6 7 9 12 14 17 就是0 3 0 0 1 2 1 2 這樣每次移動一枚棋子向左n步,相當于把對應第二排的那個數據減去n,那個數據右邊一個數加上n 這樣問題就轉變成了:有n堆石頭,每次可以從一堆中拿出一些或全部石頭給相鄰的右邊的一堆石頭,或者最后一堆減去一些或全部石頭,誰不能操作誰輸,問先手是否必勝? 關于這個問題的結論和證明網上多如牛毛,結論是:假設從最后一堆石頭開始與上一堆相間的石頭數的異或和為P,P為0時先手必敗反之必勝。比如a1,a2,a3,a4,a5?? P的值就是a5 xor a3? xor a1證明無非就是說明當不為平衡態時必然存在操作使局面進入平衡態,而局面已然是平衡態時任何操作都會破壞平衡。這里不再累述。說一下對這個問題的一些直觀認識:為了敘述方便,可以把與最后一堆石頭相間的石頭稱為有用堆(這里是我生造的一個詞)而其它堆稱為無用
堆。
□■□■□■□■□■□
如圖空心方塊表示有用堆,實心方塊表示無用堆,顯然把無用堆的石頭放到有用堆的操作都是沒有意義的,因為這次從無用堆放進多少塊石頭到有用堆,下一次操作就能將這些運進來的石頭扔給下一個無用堆或者扔掉(最后一堆石頭),而有用堆石頭的序列分毫未變,因此只需看有用堆的石頭情況即可。而有用堆的石頭放進無用堆相當于扔掉的操作,因為剛才已經證明無用堆中的石頭是不起作用毫無意義的,這樣就將問題化為了有用堆的NIM游戲!!因此只需計算有用堆的異或和就能計算出先手的勝負情況
?
//poj1704
#include<cstdio>
#include<string.h>
#include<iostream>
using namespace std;
int a[1009]={0};
void qsort(int l,int r)
{
???int i=l,j=r,mid=a[(l+r)>>1],temp;
???while(i<j)
??? {
???????while(a[i]<mid)i++;while(a[j]>mid)j--;
???????if(i<=j)
???????{
???????????temp=a[i];a[i]=a[j];a[j]=temp;
???????????i++;j--;
???????}
??? }
???if(i<r)qsort(i,r);
???if(l<j)qsort(l,j);
}
int main()
{
???int n,t,chess[1009]={0};
???scanf("%d",&t);
???while(t--)
??? {
???????int x=0,last=0;
???????scanf("%d",&n);
???????for(int i=1;i<=n;i++)scanf("%d",&a[i]);
???????qsort(1,n);
???????for(int i=1;i<=n;i++)
???????{
???????????chess[i]=a[i]-last-1;
???????????last=a[i];
???????}
???????for(int i=n;i>=1;i=i-2)
???????x=x^chess[i];
???????if (x!=0)printf("Georgia will win\n");else printf("Bobwill win\n");
??? }
??? return 0;
}
調試小結:3次WA?原因:未看清棋子順序不是從小到大!!
轉載于:https://www.cnblogs.com/philippica/p/4006972.html
總結
以上是生活随笔為你收集整理的Poj1704:staircase nim【博弈】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【学习】自学JavaScript
- 下一篇: 计算机国二复习攻略,全国计算机等级考试四