博弈 取石子

题目链接:http://acm.bupt.edu.cn/onlinejudge/newoj/showProblem/show_problem.php?problem_id=65

Description

     champ最近在和dalong玩一个取石子游戏,游戏规则很简单:有三堆石子,两人轮流取,每次任选两堆石子,然后从一堆中取走x(x>=1)个石子,另一堆中取走2*x个石子,最后不能取者输掉游戏,champ每一次都先取。
     现在,champ告诉你初始三堆石子的数量,他想知道,自己是否有必胜的策略。你可以假定champ和dalong都足够聪明,每次都会选择最优的策略。



Input
多组测试数据
每行3个正整数(范围[0,255]),表示最初三堆石子的数量。
0 0 0表示输入结束。这组数据不用处理


Output
每组输出一行
如果champ有必胜策略,那么输出"champ",否则输出"dalong"。(注意,引号不要输出)


Sample Input

1 2 0
1 4 1
0 0 0



Sample Output

champ
dalong
这个题用博弈来解决,我们用数组sg[x][y][z]来表示这个状态是P或者N,如果我们直接搜索博弈树,根据PN规则,从上到下搜索所有的子局面,
根据他们的PN得出现在的状态,时间复杂度为(n^4),由于组成的有向图是无环的(因为每次都是减少的),所以我们从下往上扩展。
对于一个状态a,b,c若它是P,则扩展的到任何可能的状态都是N,这样负责度为(n^3+ 失败点个数*n).
代码如下:
#include <iostream>
#include <stdio.h>
using namespace std;
const int N=256;
bool sg[N][N][N];
int x,y,z;
void exchange(int &a,int &b,int &c)
{
 int tmp;
 if(a>b)
 {
  tmp=b;
  b=a;
  a=tmp;
 }
 if(b>c)
 {
  tmp=c;
  c=b;
  b=tmp;
 }
 if(a>b)
 {
  tmp=b;
  b=a;
  a=tmp;
 }
}
void init()
{
 int i,j,k,t,a,b,c;
 for(i=0;i<N;i++)
  for(j=0;j<N;j++)
   for(k=0;k<N;k++)
    sg[i][j][k]=0;
 for(i=0;i<N;i++)
 {
  for(j=i;j<N;j++)
  {
   for(k=j;k<N;k++)
   {
    if(!sg[i][j][k])
    {
     //扩展i,j
     for(t=1;(i+t<N && j+2*t<N);t++)
     {
      a=i+t;
      b=j+2*t;
      c=k;
      exchange(a,b,c);
      sg[a][b][c]=1;
     }
     for(t=1;(i+2*t<N && j+t<N);t++)
     {
      a=i+2*t;
      b=j+t;
      c=k;
      exchange(a,b,c);
      sg[a][b][c]=1;
     }
     //扩展i,k
     for(t=1;(i+t<N && k+2*t<N);t++)
     {
      a=i+t;
      b=j;
      c=k+2*t;
      exchange(a,b,c);
      sg[a][b][c]=1;
     }
     for(t=1;(i+2*t<N && k+t<N);t++)
     {
      a=i+2*t;
      b=j;
      c=k+t;
      exchange(a,b,c);
      sg[a][b][c]=1;
     }
     //扩展j,k
     for(t=1;(j+t<N && k+2*t<N);t++)
     {
      a=i;
      b=j+t;
      c=k+2*t;
      exchange(a,b,c);
      sg[a][b][c]=1;
     }
     for(t=1;(j+2*t<N && k+t<N);t++)
     {
      a=i;
      b=j+2*t;
      c=k+t;
      exchange(a,b,c);
      sg[a][b][c]=1;
     }
    }
   }
  }
 }
}
int main()
{
 init();
 while(1)
 {
  scanf("%d%d%d",&x,&y,&z);
  if(!x && !y && !z)
   break;
  exchange(x,y,z);
  if(sg[x][y][z])
   printf("champ\n");
  else
   printf("dalong\n");
 }
 return 0;
}
原文地址:https://www.cnblogs.com/buptLizer/p/2163501.html