zoukankan      html  css  js  c++  java
  • 【BZOJ1022】[SHOI2008] 小约翰的游戏(Anti-Nim)

    点此看题面

    大致题意: 与普通(Nim)游戏相比,改为拿到最后一个石子的人输,求谁有必胜策略。

    前言

    为做一道博弈论的题目开始恶补博弈论。。。

    感觉现在理解能力不太行,就这么简单一道题看题解还看了半天。。。

    分类讨论

    对于这道题,我们需要分三类进行讨论:

    1. 每堆只有一个石子。显然此时每人每次必然是将一堆取走,因此偶数堆时先手赢,奇数堆时后手赢。若用(SG)函数表示,则(SG=0)时先手赢,(SG>0)时后手赢。
    2. 只有一堆石子个数大于(1)。则假如除此之外还剩奇数堆石子(个数都为(1)),先手可以把这堆石子取完;假如除此之外还剩偶数堆石子,先手可以留下(1)个石子。两种方式都把局面转化成了第一种情况里奇数堆的情况,因此先手(后手的后手)就必胜了。若用(SG)函数表示,显然一个大于(1)的数和若干(1)的异或值大于(0),因此(SG>0)时先手赢。
    3. 有大于一堆石子个数大于(1),即一般情况。考虑在不断取石子的过程中,必然有某一刻第三类情况被转化为了第二类情况(注意,不可能直接跳过第二类转化为第一类情况),而第二类情况相当于是(SG>0)时获胜。因此,二人都需要尽可能使自己的(SG)值大于(0),于是此时这个问题就变成了普通(Nim)游戏:(SG>0)时先手赢,(SG=0)时后手赢。

    综上所述,先手赢的条件为每堆只有一个石子时(SG=0),或存在石子个数大于(1)的堆时(SG>0)

    代码

    #include<bits/stdc++.h>
    #define Tp tmeplate<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 50
    using namespace std;
    int n;
    int main()
    {
    	RI Tt,i,x,SG,cnt;scanf("%d",&Tt);W(Tt--)
    	{
    		for(SG=cnt=0,scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&x),SG^=x,x>1&&++cnt;//统计SG值,cnt记录1的个数
    		puts((cnt?SG:!SG)?"John":"Brother");//若有1,则SG>0时先手胜;若无1,则SG=0时先手胜
    	}return 0;
    }
    
  • 相关阅读:
    SQLServer中查询的数字列前面补0返回指定长度的字符串
    Http Module 介绍
    SQLite中使用时的数据类型注意
    SQLite中的PRAGMA语句攻略
    Sqlite中使用rowid来表示行号,用于分页。
    Sqlite基础及其与SQLServer语法差异
    SQLite中的日期基础
    Asp.net页面无刷新请求实现
    CSS3实现的渐变按钮,在IE7、IE6下的滤镜使用。
    如何给网站页面添加图标?
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ1022.html
Copyright © 2011-2022 走看看