1. 程式人生 > >POJ 1704 Georgia and Bob(階梯博弈)題解

POJ 1704 Georgia and Bob(階梯博弈)題解

n-2 有一個 n-1 seed class ++ article scanf clas

題意:有一個一維棋盤,有格子標號1,2,3,......有n個棋子放在一些格子上,兩人博弈,只能將棋子向左移,不能和其他棋子重疊,也不能跨越其他棋子,不能超越邊界,不能走的人輸

思路:可以用階梯博弈來做。

那麽先簡單講一下階梯博弈:

有一個x階階梯,每一階都有一定數量的石頭,每次只能把某一階梯上任意數量(不為0)的石頭往下移動一階,最多只能移動到地面,不能移動的敗。這裏先手的策略是這樣:對奇數階階梯的石子進行Nim博弈,異或和為0必敗。為什麽不用考慮偶數呢?因為如果後手的人把m顆石頭從2*n階移到2*n-1階,那麽先手的可以把m顆石頭從2*n-1階移到2*n-2階,重復操作直到到0階即地面,所以我們可以不考慮偶數階的石子數。所以奇數階的石子被移到下一階時,我們可以直接認為這些石頭被移除了。那麽直接Nim博弈就可以了。

返回這道題,如圖,假如我們把棋子A向左移動一定數量,那麽我們可以把棋子B向左移動相同數量來保證AB間隔不變,這裏就和階梯博弈時移動偶數階石子奇數階石子數量不變是一樣的。所以我們從最後一個棋子開始往前分組,兩個一組,每一組的間隔就是奇數階石子個數。講一下為什麽從最後面開始分,因為最後一個間隔不會因為其他間隔的變化而變小,所以必須作為奇數階石子保持不變(強行這樣理解)。

技術分享圖片

參考:階梯博弈算法詳解(尼姆博弈進階)

代碼:

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include
<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> typedef long long ll; const int maxn = 1000 + 10; const int seed = 131; const ll MOD = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; int a[maxn]; int main(){
int T, n; scanf("%d", &T); while(T--){ scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); sort(a + 1, a + n + 1); int ans = 0; for(int i = n; i > 0; i -= 2){ ans ^= (a[i] - a[i - 1] - 1); } if(ans == 0) printf("Bob will win\n"); else printf("Georgia will win\n"); } return 0; }

POJ 1704 Georgia and Bob(階梯博弈)題解