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

本文解析了一道综合性的博弈题目,涉及四种不同棋子(王、车、马、王后)的走法规则,并通过转换为取石子问题,分别探讨了每种棋子对应的胜负判断逻辑及特殊情况,最后给出了实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接: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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值