博弈论学习中

/*HDU 4315  以便自己学习以及回顾*/

一列棋子,中间空格若干。有一个棋子记为king ,双方轮流移动棋子,可以走任意步数,不能越过其他棋子,走到顶部移除。把king移到顶部的选手为胜利。

此题的简化版本是不考虑King的存在,双方一直走到不能走的一方为负。此时的解法是根据人数的奇偶性:把人从上顶向下的位置记为a1,a2,...an, 如果为偶数个人,则把a(2i-1)和a(2i)之间的距离当做一个Nim堆,变成一共n/2堆的Nim游戏;如果为奇数个人,则把山顶到a1的距离当做一个Nim堆,a(i*2)到a(i*2+1)的距离当做Nim堆,一共(n+1)/2堆。

 考虑King的情况和上述版本几乎一致,只要把King当作普通人一样处理即可。

除了两种特殊情况:1. 当King是第一个人时,Alice直接胜 2. 当King是第二个人且一共有奇数个人时,第一堆的大小需要减1。

核心:

模型转化,从最后面的开始,两个棋子构成一个nim石子堆,将复杂的棋盘问题分解成nim问题。在各自空间内,相互独立开来。

证明过程:

不存在king的情况下,把棋子的移动转化为nim博弈的操作过程,结果等效。若存在的king,当king不为第一个时,情况其实是等效的,只是在局部操作的时候,可以通过最后步的操作来,在游戏过程中,从nim博弈的必胜态,直接把king移到顶部,来获胜。

关键是特殊情况2。把第一堆的个数减一,就是为了防止,在过程中将king移到顶部。即,过程中king最多移到第一个,而不能到达顶部。当nim博弈结束时,即所有的棋子紧挨了,即把每一堆都取完了。而这个时候,面对P态的选手,只能移动第一个棋子到顶部,,这个时候,另一个选手取胜。

 

#include<iostream>
#include<cstring>
#include<stdio.h>
#include<cmath>
#include<algorithm>
using namespace std;
int n,k;
int f[1010];
int mark;
int main()
{
 int i;
 while(scanf("%d%d",&n,&k)!=EOF)
 {
  mark=0;
  for(i=0;i<n;i++)
   scanf("%d",&f[i]);
  if(k==1){printf("Alice\n");continue;}
  if(n%2==1)
  {
   if(k==2) mark=f[0]-1;
   else mark=f[0];
   for(i=1;i<n;i=i+2)
   {
    mark^=(f[i+1]-f[i]-1);
   }
  }
  else
  {
   for(i=0;i<n;i+=2)
   {
    mark^=(f[i+1]-f[i]-1);
   }
  }
  if(mark==0) printf("Bob\n");
  else printf("Alice\n");
 }
 return 0;

已标记关键词 清除标记
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页