您的位置:首页 > 其它

poj 1704 Georgia and Bob(博弈)

2012-03-19 20:52 393 查看
【题目大意】:一个1*M的棋盘上有N个棋子,初始位置一定,两人轮流操作,每次移动一枚棋子,要求只能向左移且至少移动一格,

而且不能到达或经过以前有棋子的格子,谁无法移动棋子就算输。

【解题思路】:1)按照位置进行排序,然后将每两个分成一组

2)接下来,分下面两种情况讨论:

1、先手移动任意组中的左边的一个,那么对于后手的最优策略便是将该组右边的一个移动相同的步数

2、先手移动任意组中的右边的一个,我们就要考虑左右之间的间隔差来判断最优策略

3)分析到这里,其实问题变得更简单了,主要是更熟悉了,接下来看看下面的这个问题:

给定N堆石子,每堆里面的石子个数都是非负的。每次可以把第i堆中的任意颗石子移动到第i + 1堆中(1 <= i < N),或者第N堆的石子扔掉任意颗。如果某人不能继续操作则判负。

(o(∩_∩)o ~~熟悉勒)

4)对于这一类的取石子问题,我们一般有如下的结论:设第i堆的石子数为ai。设ans=aN xor a(N - 2) xor a(N - 4) xor ... xor a2(a1),若ans=0则先手必败,否则先手必胜。

5)接下来,证明:

首先,显然有当各堆的石子数均为0的时候先手必败。此时ans=0。

其次,要证明该结论,只需证明如果ans<>0的时候一定可以通过一步操作将ans变为0,且ans=0的时候任意操作均会使得ans<>0。

1、先证明ans<>0的时候可以将ans->0。设此时的ans=x且x的最高位"1"是第k位,则一定存在某个 i=总堆数-2n(n ∈ N),使得a(i)的第k位也为1,否则第k位的异或运算的值不可能为1。将ai改变为ai' = x xor ai,由于ai的第k位以上的位不会改变,第k位由1变成了0,易知ai'<ai。故只需将ai的石子向右移动(ai-ai')个即可。由奇偶性可知ai右边的一堆不参与运算。
此时ans=x xor ai xor ai' =x xor ai xor (x xor ai) = 0。
2、再证ans=0时无论怎么操作均会使ans<>0。设x=0时设将ai改变成了ai',显然ai<>ai'。
此时ans=x xor ai xor ai' = ai xor ai' <> 0。

~~~结束了

【代码】:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <cctype>
#include <map>
#include <iomanip>

using namespace std;

#define eps 1e-8
#define pi acos(-1.0)
#define inf 1<<30
#define pb push_back
#define lc(x) (x << 1)
#define rc(x) (x << 1 | 1)
#define lowbit(x) (x & (-x))
#define ll long long

int n;
int p[10100];
int T, i, j, a, cnt, t;

int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n);
cnt=0;
for(i=1; i<=n; i++) scanf("%d",&p[i]);
sort(p+1,p+n+1);
int k=1;
for(i=n; i>=2; i-=2){
t=p[i]-p[i-1]-1;
cnt=cnt^t;
}
if(n%2==1) cnt=cnt^(p[1]-1);
if(cnt!=0) cout << "Georgia will win" << endl;
else cout << "Bob will win" << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: