当前位置: 代码迷 >> 综合 >> HDOJ 5754 (2016多校联合训练 Training Contest 3) Life Winner Bo
  详细解决方案

HDOJ 5754 (2016多校联合训练 Training Contest 3) Life Winner Bo

热度:57   发布时间:2023-12-06 03:15:49.0

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5754



一道博弈大汇总,一道题当做四道题来做=.=,题意是给我们四种棋子,每种棋子的走法不同,问我们谁会赢。

1.王:

王的行走方式是只能向下或者向右或者向右下移动一格。

王我们可以直接分析必胜点和必败点,首先我们的终点就是必胜点,而必胜点的左上三个格子都是必败点,我们这样推就会发现必胜点(O)和必败点(X)会按一下方式排列。

OXOXOXOXOXOXOXOXOXOXO

XXXXXXXXXXXXXXXXXXXXXXXX

OXOXOXOXOXOXOXOXOXOXO

XXXXXXXXXXXXXXXXXXXXXXXX

OXOXOXOXOXOXOXOXOXOXO

也就是说只要行和列都是奇数,那么先手就会输,其他情况都是先手赢。

2.车:

车的行走方式是能向下或者向移动任意格子。

这个问题其实我们可以转换成取石子的方式,有n,m个石子的两堆石子,我们可以一次任意从两堆中的一堆中取任意个石子,问我们谁能够取到最后一个。

关于这个问题我们很容易找到一个平衡点,那就是当两堆的个数相等的时候,当两堆个数相等的时候很明显下一个人只能够破坏这个平衡,而下一个人又可以恢复这个平衡,所以两堆相等就是必胜点,也就是说如果一开始n,m相等,那么先手就输了,不等则先手赢。

3.马:

马的行走方式是走日字,只能向右下的方向移动。

首先马和车一样,存在这个平衡点,那就是n和m相等的时候,但是n,m相等并不代表就一定能够移动到终点,必须得存在(n-1)%3==0才行,如果一开始就在这个平衡点上那么先手就输了,如果第一步就能够移动到这个平衡点上,那么先手就赢了,其他的情况都应该是没有结果。

4.王后:

我相信大多数的选手卡在这题的话,都是卡在这个王后上,王后的移动方式是可以向下或者向右或者向右下移动任意格子,那么换成是取石子的话就是有n,m个石子的两堆石子,我们可以一次任意从两堆中的一堆中取任意个石子或者两堆同时取任意个旗子,问我们谁能够取到最后一个。

这个是威佐夫博弈,相信很多没有听过这个威佐夫博弈的同学比赛的时候都想通过打表俩解决,首先,打表肯定是对的,但是小编觉得,打表真的很难保证表的正确性,相信很度同学度觉得自己明明表是打的对的,为什么就是WA,肯定什么地方多多少少还是有问题的,那么小编这里就直接用威佐夫博弈的公式来求解。

#include <cmath>
#include <cstdio>
#include <iostream>
typedef long long ll;
using namespace std;
int main()
{int T;scanf("%d", &T);while(T--){int type, n, m;scanf("%d%d%d", &type, &n, &m);if(type == 1){if(n%2!=0 && m%2!=0) printf("G\n");else printf("B\n");}if(type == 2){if(n == m) printf("G\n");else printf("B\n");}if(type == 3){if((n==m&&(n-1)%3==0)) printf("G\n");else if((n==2&&m==3) || (n==3&&m==2)) printf("B\n");else if((n-1==m-2)&&(n-2)%3==0 || (n-2==m-1)&&(n-3)%3==0) printf("B\n");else printf("D\n");}if(type==4){n--,m--;if(n<m)swap(n,m);int k=n-m;n=(int)(k*(1+sqrt(5))/2.0);if(n==m) printf("G\n");else printf("B\n"); }}return 0;
}


  相关解决方案