one of Algorithm ---- 博弈论 NIM

one of Algorithm ---- 博弈论

原理:游戏都建立在双方都有最优策略的情况下

典型例题(level1)
特点:所走的步数是固定的 多选一

例1:取石子游戏之一
有两个游戏者:AA和BB,有nn颗石子。
约定:两人轮流取走石子,每次可取1,21,2或33颗。AA先取,取走最后一颗石子的人获胜。

问题:AA有没有必胜的策略?

分析:这是小学必备奥数题之一,我们可以很容易的知道,
当n为0,4,8,12……4的倍数时,A必定会输,因为不论A取多少,B只要和A共同取走4即可;当n不为0,4,8,12……时,A只需要将n取成4的倍数,这样就变成了B先取,B一定会输,所以A一定会赢。

!!!经过我们的分析发现,对这个游戏而言,0,4,8,12……这些状态是对于先手的必败状态,而其他状态是对于先手的必胜状态。

总结:

如果我们推广一下,每次不一定取1,2,3颗,而是取1∼m颗,那么我们就可以得到,
如果n%(m+1)=0,即为先手必败状态,否则为先手必胜状态。而这个游戏就是著名的巴什博弈(Bash Game)

在这里插入图片描述

题型总结

1、平等组合游戏
两人游戏。
两人轮流走步。
有一个状态集,而且通常是有限的。
有一个终止状态,到达终止状态后游戏结束。
游戏可以在有限的步数内结束。
规定好了哪些状态转移是合法的。
所有规定对于两人是一样的。
因此我们的例1提到的游戏即为一个平等组合游戏,但是我们生活中常见的棋类游戏,如象棋、围棋等,均不属于平等组合游戏,因为双方可以移动的棋子不同,不满足最后一个条件;而我们后续提到的游戏,以及博弈中的其他游戏,基本属于平等组合游戏

第二种题型
在这里插入图片描述

重要原理:

!!!特殊情况
如果仅仅是两堆石子,那么上述两个问题很好解决:
1〉当两堆石子数目相等的时候,当前局面为必败局面,否则为必胜局面,显然,两堆均为0颗是满足这个方法的;
2〉如果当前局面是必胜局面,那么从石子较多的那一堆里面取,使得两堆石子数相等,这样便转化到了必败局面。

大于两堆的情况:

1〉把所有堆的石子数目用二进制数表示出来,当全部这些数按位异或结果为0时当前局面为必败局面,否则为必胜局面;
2〉(定理0)一组自然数中必然存在一个数,它大于等于其它所有数按位异或的结果。因此在必胜局面下,因为所有数按位异或的结果是大于零的,那么通过一次取,将这个(大于其它所有数按位异或的结果的)数下降到其它所有数按位异或的结果,这时局面就变为必败局面了。

简单介绍  异或运算的性质及应用

概念
异或是一种基于二进制的位运算,用符号XOR或者 ^ 表示,其运算法则是对运算符两侧数的每一个二进制位,同值取0,异值取1。它与布尔运算的区别在于,当运算符两侧均为1时,布尔运算的结果为1,异或运算的结果为0。

#简单理解就是不进位加法,如1+1=0,0+0=0,1+0=1。

应用
1. 交换两数的值

所有的程序教科书都会向初学者指出,要交换两个变量的值,必须要引入一个中间变量。但如果使用异或,就可以节约一个变量的存储空间: 设有A,B两个变量,存储的值分别为a,b,则以下三行表达式将互换他们的值 表达式 (值) :

A= A XOR B (a XOR b)

B= A XOR B (b XOR a XOR b = a)

A= A XOR B (a XOR b XOR a = b)

2. 找出重复数字

1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现
一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空
间,能否设计一个算法实现?

解法一、显然已经有人提出了一个比较精彩的解法,将所有数加起来,减去1+2++1000的和。
这个算法已经足够完美了,相信出题者的标准答案也就是这个算法,唯一的问题是,如果数列过大,则可能会导致溢出。
解法二、异或就没有这个问题,并且性能更好。
将所有的数全部异或,得到的结果与1231000的结果进行异或,得到的结果就是重复数。

例一

在这里插入图片描述
0 的作用仅仅是改变后续操作的奇偶性,因此 {0}0 的个数 aa 可以对 2 取模。
接下来,我们先不考虑 0 的存在。

先手取了1 之后,后手必定取 {1}1 ,然后先后手依次是 {2,1,2,1,2,1\;

先手取了 22 之后,后手必定取 22,然后先后手依次是 {1,2,1,2,1,2}。

综上,观察到取的方式一定是 1,2 交替(除了开头)。

代码实现

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        long long a,b,c;
        cin>>a>>b>>c;
        //若bc缺少任意一个 都是后手赢
        if((b!=0&&(a+(b-1>c))%2==0)//(a是奇数 和 b-1>c 两个条件必须同时满足)
        ||
        (c!=0&&(a+(c-1>b))%2==0)) cout<<"First"<<'\n';
        else cout<<"Second"<<'\n';
    }
    return 0; 
}

二进制最低位为1时,就是奇数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值