poj 1704 小小的博弈问题

来源:互联网 发布:电子商务app软件多少钱 编辑:程序博客网 时间:2024/05/17 23:42

  

  题目大意:在一个正整数数轴上,放着一些棋子,两人博弈,

  每个人可以选取任意一个棋子,把它往左(与正方向相反)移动若干步,条件是移动过程中不能够经过另一些棋子。

   问先手的必胜必败态;


   关键在于模型转换,举个例子;

                        A----------------B---------------------C--------------------D

                               

                                   ========〉

                                        C左移

                       A----------------B-----C-------------------------------------D

                相当于从BC中取出一些长度放到CD中,如果把它看成石子的话,就是从BC中取了一些石子给CD。

    所以可以把n个棋子转化为 n-1段长度,长度可以看成棋子个数:

    那么问题楼梯nim:

               这是一个在n级台阶上进行的游戏,每级台阶上有一定数量的硬币。

               第i级台阶上硬币的数目为 xi 。

               参与游戏的两名玩家轮流执行如下操作:选择一个台阶i,并把第i级台阶上的若干枚硬币移动到第i-1级台阶上。

               第0级台阶是地面,落在这上面的硬币将被清除。把最后一枚硬币移动到地面上的玩家获胜。

  

       这个问题中,偶数台阶上的棋子是没有用的,

       因为如果把偶数台阶上的棋子放到奇数台阶上, 对该奇数台阶以后的操作没有影响,因为在对于该奇数台阶进行操作时,

       可以“顺便”把这些从上一级偶数台阶上流下来的棋子放到下一级偶数台阶,直到别放到0台阶,所以,把棋子放到偶数台阶上,就等于扔掉了。


      于是就变成了奇数台阶上的取石子游戏,xor一下奇数台阶上的石子数即可。

  

program lmd;var    t,ans,i,n,x,maxn:longint;    a,b:array[0..1000]of longint;procedure sort(l,r:longint);var i,j,x,z:longint;begin   i:=l;j:=r;x:=a[(l + r)shr 1];   repeat     while a[i] < x do  inc(i);     while a[j] > x do  dec(j);     if i <= j then       begin         z:=a[i]; a[i]:=a[j]; a[j]:=z;         inc(i); dec(j);       end;   until i > j;   if l<j then sort(l,j);   if i<r then sort(i,r);end;begin     assign(input,'1704.in');     assign(output,'1704.out');     reset(input);rewrite(output);     read(t);     for t:=1 to t do       begin         ans:=0;   maxn:=0;         read(n);         for i:=1 to n do read(a[i]);         sort(1,n);         for i:=1 to n do b[i]:=a[i]-a[i-1]-1;         for i:=n downto 1 do           if (n-i)and 1=0 then              ans:=ans xor b[i];         if ans=0 then writeln('Bob will win')           else writeln('Georgia will win');       end;     close(input);close(output);end.