尼姆博弈 (附:HDU1850)

版权声明:本文为博主原创文章,转载时请注明原文地址=w=,希望对您有所帮助 https://blog.csdn.net/Eirlys_North/article/details/53063929

尼姆博弈:

三堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜

这种情况与二进制有着很大的关系,

我们用(a,b,c)来表示某种局势,

那么(0,0,0)必然为奇异局势

(0,n,n)也是种奇异局势

因为如果对手在其中一堆取m个石子(m<=n),那么你也可以在另外一堆中取m个,他取几个你就取几个,到最后有一堆变为0的时候,你再取完另一堆胜利(满满的套路=。=)。

直接说结论吧:

对于任意的奇异局势(a,b,c),都有a^b^c=0(^为异或运算)

对于任意的非奇异局势(a,b,c),假设a<b<c,将它变为奇异局势的方法是:将c变成a^b。

原理:

因为a^a=0

所以a^b^c=a^b^(a^b)=0,

所以只需将c-(a^b)即可。

来来来,这里有个栗子,还热乎乎的呢=w=:

有个非奇异局势(14,21,39),

因为14^21=27,39-27=12,所以从39中拿走12个物体即可达到奇异局势(14,21,27)。


这里还有个栗子,买一赠一哦=w=

我们来实际进行一盘比赛看看:

        甲:(7,8,9)->(1,8,9)奇异局势
        乙:(1,8,9)->(1,8,4)
        甲:(1,8,4)->(1,5,4)奇异局势
        乙:(1,5,4)->(1,4,4)
        甲:(1,4,4)->(0,4,4)奇异局势
        乙:(0,4,4)->(0,4,2)
        甲:(0.4,2)->(0,2,2)奇异局势
        乙:(0,2,2)->(0,2,1)
        甲:(0,2,1)->(0,1,1)奇异局势
        乙:(0,1,1)->(0,1,0)
        甲:(0,1,0)->(0,0,0)奇异局势
        甲胜。

于是,我们又发现了一些神奇而显然的性质=w=:

性质1:对于某个局面(a1,a2,...,an),若a1^a2^...^an!=0,

一定存在某个合法的移动,将ai改变成ai'后满足a1^a2^...^ai'^...^an=0。

分析:令res=a1^a2^......an,设res的最高位为pos(那pos的数肯定为1啦),

          那么一定存在某个ai,它的二进制在pos位上也是1,(否则k的最高位那个1是怎么得到的)。

          异或res后这位变为0,

          这时ai^res<ai一定成立。

         则我们可以将ai改变成ai'=ai^res,此时a1^a2^...^ai'^...^an=a1^a2^...^an^res=0。

注意:虽然它一定存在合法的移动(一定有a[i]使 ai^res<ai一定成立)使之变成奇异局势,

     但并不是每一堆都可以进行操作的,只有当a[i]>a[i]^res 的时候才可以对这一堆进行操作

 


拓展: 

任给N堆石子,两人轮流从任一堆中任取(每次只能取自一堆),取最后一颗石子的人获胜,问先取的人如何获胜?

根据上面所述,N个数异或即可。

如果开始的时候T0,那么先取者必败

如果开始的时候T>0,那么只要每次取出石子使得T0,即先取者有获胜的方法。

 

性质2:对于某个局面(a1,a2,...,an),若a1^a2^...^an=0,一定不存在某个合法的移动,将ai改变成ai'后仍满足a1^a2^...^ai'^...^an=0。

 

获胜情况对先取者进行讨论:

异或结果为0,先取者必败,无获胜方法。后取者获胜;

结果不为0,先取者有获胜的取法。

 

HDU1850

判断先手能否赢,可以赢的话输出第一步的方案数

var
    n,t                 :longint;
    i                   :longint;
    a                   :array[0..110] of longint;
function work(t:longint):longint;
var
    j:longint;
    ans:longint;
begin
   ans:=0;
   for j:=1 to n do
     if (a[j]>a[j] xor t) then inc(ans);//判断能否对当前堆进行操作
   exit(ans);
end;

begin
   read(n);
   while (n<>0) do
   begin
      t:=0;
      for i:=1 to n do
      begin
      read(a[i]);
      t:=t xor a[i];
      end;
      if t=0 then writeln(0) else writeln(work(t));
      read(n);
   end;
end.



综合巴什博弈、尼姆博弈给出】

任给N堆石子,两人轮流从任一堆中任取(每次只能取自一堆),规定每方每次最多取K,取最后一颗石子的一方获胜.问先取的人如何获胜?

与上面的问题比,这个更复杂一些,我们可以这样做:

Bi=Ai mod(K+1)

定义T‘=B1 xor B2 xor ... xor Bn

如果T‘=0 那么没有获胜可能,先取者必败

如果T>0 那么必然存在取的方法,使得T‘=0先取者有获胜的方法

假设对方取了在Ai中取了r(r<=K)

如果Ai中剩下的石子多于K 那么就在Ai中取走K+1-r个,则Bi不变 ,T‘不变

如果Ai<=K 那么我们需要重新计算BiT按照上面的方法来做就可以了

                              ——by Eirlys

转载请注明出处=w=


猜你喜欢

转载自blog.csdn.net/Eirlys_North/article/details/53063929