zoukankan      html  css  js  c++  java
  • 【笔记】简单博弈

    前言

    大半年前写的东西了,自己真的在走下坡路

    例题

    A , B进行游戏。A先开始,轮流将n减去{2,3,4,5,6}中的一个数,谁最后无法进行减法了,就输了。
    给定n。A,B都采用最优策略,问A是否会赢。

    状态

    设f[i]表示当前的数是i的时候,对于当前的先手来说是否会赢
    f[i]=true,则赢
    f[i]=false,则输

    转移

    当先手A操作一次后,问题转移为了对于当前先手B,对(n-i)进行操作

    必胜转移到必败,必败转移到必胜

    就是说
    从f[i]转移到的所有状态f[i-2],f[i-3]..f[i-6]如果都是必胜态,那么f[i]则为必败态
    从f[i]转移到的所有状态f[i-2],f[i-3]..f[i-6]如果都是必败态,那么f[i]则为必胜态

    初始化

    f[0]和f[1]对于先手来说必败
    f[0]=false,f[1]=false
    f[2]则对于先手来说必胜,f[2]=true

    碎碎念

    前几天上数学课的时候老师讲了一个类似的题,当时想到了DP。

    高级

    当n%8=1或0时,必败。否则必胜

    博弈DP的特征

    博弈DP解决的是两人轮流操作,且没有平局的 #两人博弈游戏#
    写代码的话一般是#人人为我#类型,即用其他状态向自己转移
    更一般的,博弈没有固定搜索顺序,习惯用记忆化搜索

    problem1【第一类,两人博弈类型】

    状态

    f[i][j]表示当前手上数字为i,上一个减去的数是j的时候是必胜还是必败

    转移

    f[i][j]转移到f[i-r][1~r],其中1<=r<=k*j

    复杂度

    O(n^3)
    没有代码

    problem2-1【第二类,组合两人博弈类型】

    A,B两人游戏,现在有a1,a2,...an共n个数, 轮流操作,每次可以对任意一个数操作,最后谁无法操作谁就输了。操作为将这个数减去{1,2,3,4,5,6}中的一个。

    范围:n<=(10^5),a_i<=(10^5)

    分析

    相当于有n个#二人博弈问题#,称之为#组合二人博弈问题#

    状态

    初始蒟蒻
    设计一个n维的f[1][2][3]...[n],表示当前态
    这玩意肯定不行,所以要用sg

    mex运算

    设S 表示一个非负整数集合。定义mex(S)为求出不属于集合S 的最小非负整数的运算。即:
    mex(S) = min{x|x(in) N, x$ otinS}, 比如mex{0,2,3} = 1

    sg函数(Sprague-Grundy 是两个人的名字)

    sg[i]表示的是数字i这个状态的sg值
    sg值:取出所有能转移到的sg值的前继状态集合{sg[1],sg[i-2]...sg[i-6]},则i的sg函数的值为这个集合的mex运算结果,即sg=mex{sg[1],sg[i-2]...sg[i-6]}

    必败态的sg为0,必胜态的sg值为非零

    对于这个题,sg[0]必败,所以s[0] = 0,s[1]的前继状态的集合为{s[0]},所以sg[1] = 1
    sg[2]的前继状态集合为{sg[0] = 0,sg[1] = 1},sg[2] = 2
    sg[3]的前继状态集合为{sg[0] = 0,sg[1] = 1,sg[2] = 2},sg[3] = 3
    sg[4] = 4,sg[5] = 5,sg[6] = 6
    sg[7]的状态集合为{sg[1] = 1, sg[2] = 2, sg[3] = 3,sg[4] = 4, sg[5] = 5, sg[6] = 6},sg[7] = 0
    sg[8] = 1,sg[9] = 2
    事实上,对于sg[8]和sg[9],先手必须把状态转移到sg[7],让下一个人必败

    对于这个题,有sg值就可以不用n维了吗?不行。他还是这个样子:
    sg[a1][a2]...[an]

    sg定理

    n个游戏的sg值 等于 每个游戏的sg值异或起来
    sg(a1,a2...an) = sg(a1) xor sg(a2) ... xor sg(an)

    所以我们分开讨论每个游戏,最后异或起来

    没有代码

    problem2-2——NIM游戏

    n <= (10^5) a_i <= $10^9¥

    problem3-1【第三类,可以转移到组合博弈】

    n+1堆石子,最左边一堆石头有2012个,两个人分别进行操作。一次操作可以选取两堆不同的石堆分别增加或减少一个石子(一加一减,或给已经不剩石子的堆加一个都是允许的)。为了保证游戏会在有限步内结束,规定所选的两堆中右边的那一堆一定要包含奇数个石子,无路可走者输.问先手是否必胜?

    problem3-2

    problem3-3

    必败态

    除了最左边,每一堆都是偶数个石子,所以不讨论每一堆的实际个数,只讨论奇偶
    a1,a2...an等于0或1

    problem3-4

    不关心石子个数,只关心奇偶
    因为独立的是石子而不是石子队
    因为我们的游戏单位是石子,两个石子的sg值相互抵消为0,所以只关心奇偶
    NIM的游戏单位是石子堆

    状态

    sg[i]在第i堆的石子的sg值

    转移

    sg[i] = mex(sg[j]^sg[k])

  • 相关阅读:
    HNOI2017影魔
    CQOI2015任务查询系统
    ZJOI2007报表统计
    python学习之 getattr vs __get__ vs __getattr __ vs __getattribute__ vs __getitem__
    jenkins+supervisor实现django项目的自动部署(ubuntu)
    gunicorn+anaconda+nginx部署django项目(ubuntu)
    uwsgi+anaconda+nginx部署django项目(ubuntu下)
    es过滤集提升权重
    一道Python面试题:给出d = [True, False, True, False, True],请利用列表d,只用一句话返回列表[0,2,4]
    从一道Python面试题说起(大神勿入)
  • 原文地址:https://www.cnblogs.com/ZhengkunJia/p/13795148.html
Copyright © 2011-2022 走看看