POJ 1704 Georgia and Bob【Nim博弈】
POJ 1704 Georgia and Bob
http://poj.org/problem?id=1704
大意:Georigia和Bob玩棋子游戏,棋子排成一行,类似于落入x坐标上,最左端
为原点0所在位置,棋子i坐落于x轴上的chess[i](chess[i]>0)位置,
游戏规则如下:
1.每人每次可以且只能移动一个棋子
2.每次移动棋子的格子数不限
3.只能向左移动棋子
4.移动过程中不能覆盖或越过其它棋子
5.当谁没有棋子可以移动时,就输了
6.两人轮流移动石子,女士优先,Georigia总是先移动
7.最左端所在坐标为0,亦即放在1位置的棋子不能再往左移
假设两人一样聪明,给定棋子的初始位置,判断谁将是赢家。
分析:
1.将棋子按位置升序排列,从前往后将其两两组成一对。
如果棋子数为奇数,则假设0位置上放有一棋子,与原先位置最小的棋子组成
一对,剩下的依旧从前往后两两组成一对.
2.从(1)的分组中取出两组相邻的棋子,假设其位置分别为
(chess[i],chess[i+1]),(chess[i+2],chess[i+3]),
此时若我们移动chess[i+2]若干步,对手总能移动chess[i+3]相同步数
故这里chess[i+1]与chess[i+2]之间有多少空格对结局并没有影响,即
每组棋子的前一个与其前面一组的后一个棋子所在位置的距离对结局并没有影响
故本题我们只需考虑同一组棋子间的距离
3.对(2)建模,假设现已将n组棋子分为s=(n+1)/2组,每组前后两棋子间
的距离分别为dis[0],dis[1],dis[2]...dis[s-1],
那么现在问题就演变为有s堆石子,其中第i堆石子个数为dis[i](0<=i<s),
两人轮流取石子,每次可选任意一堆石子取,且每次至少取一个,多者不限,最后取光者取胜。
现在就是最裸的Nimm Game问题了,套用模型即可.
1 #include<stdio.h>
2 #include<algorithm>
3 using namespace std;
4 const int N = 1000+1;
5 const int Zero = 0;//0所在位置为最左端,亦即放于1位置的棋子不能再左移
6 int chess[N];//chess[i]存储棋子的摆放位置
7 int main()
8 {
9 int cases;
10 scanf("%d",&cases);
11 while(cases--)
12 {
13 int n;
14 scanf("%d",&n);//n个棋子
15 for(int i=0;i<n;i++)
16 scanf("%d",&chess[i]);//棋子位置
17
18 sort(chess,chess+n);//必须排序,其输入不一定是按序输入的!
19
20 int ans = 0;
21 int curid = 0;
22 if(n&1)//若n为奇数,则将第一个与Zero绑定
23 {
24 ans = chess[curid]-Zero - 1;
25 curid++;
26 }
27 else//n为偶数,绑定前两个
28 {
29 ans = chess[curid+1]-chess[curid] - 1;
30 curid+=2;
31 }
32
33 curid++;//将curid指向每组的后一个棋子所在位置
34 while(curid<n)//以后每两个绑定在一组
35 {
36 int cur = chess[curid]-chess[curid-1]-1;
37 ans = ans^cur;
38 curid+=2;
39 }
40
41 if(ans == 0)
42 printf("Bob will win\n");
43 else
44 printf("Georgia will win\n");
45 }
46 return 0;
47 }