博弈论(Nim游戏的扩展)

news2024/9/21 2:38:38

公平组合游戏ICG

若一个游戏满足:
1.由两名玩家交替行动;

2.在游戏进程的任意时刻,可以执行的合法行动与轮到哪名玩家无关;

3.不能行动的玩家判负;
则称该游戏为一个公平组合游戏。
NIM博弈属于公平组合游戏,但城建的棋类游戏,比如围棋,就不是公平组合游戏

必胜状态和必败状态

必胜状态,先手进行某一个操作,留给后手是一个必败状态时,对于先手来说是一个必胜状态。即先手可以走到某一个必败状态。
必败状态,先手无论如何操作,留给后手都是一个必胜状态时,对于先手来说是一个必败状态。即先手走不到任何一个必败状态。

  • 如果当前局面所有石堆的异或和(Nim和)为0,那么无论如何操作,当前玩家都处于必败态;如果当前局面是必败态,则无论如何操作,另一方总有必胜的策略。

  • 如果当前局面所有石堆的异或和(Nim和)不为0,那么当前玩家可以通过正确的策略使对手进入必败态,因此当前玩家处于必胜态。如果当前局面是必胜态,玩家可以通过正确操作将局面转化为必败态,从而保证胜利。

异或运算三个性质:
①任何数和 0做异或运算,结果仍然是原来的数
②任何数和其自身做异或运算,结果是 0
③异或运算满足交换律和结合律 

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int main() {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int n; cin >> n;
    int res = 0;
    for(int i = 0; i < n; i++){
        int x; cin >> x;
        res^=x;
    }
    if(res) cout << "Yes\n";
    else cout <<"No\n";
    return 0;
}

台阶-Nim游戏

与经典Nim的区别

  • 在经典的Nim游戏中,石子堆是独立的,而在台阶-Nim中,台阶之间可能存在关联。例如,某个台阶上的石子数量可能会影响其他台阶的策略

 

 结论:

此时我们需要将奇数台阶看做一个经典的Nim游戏,如果先手时奇数台阶上的值的异或值为0,则先手必败,反之必胜。

证明:
先手时,如果奇数台阶异或非0,根据经典Nim游戏,先手总有一种方式使奇数台阶异或为0,于是先手留了奇数台阶异或为0的状态给后手,此时先手必赢。
于是轮到后手:
①当后手移动偶数台阶上的石子到奇数台阶上时,先手只需将对手移动的石子继续移到下一个台阶,这样奇数台阶的石子相当于没变,奇数异或和仍是非0于是留给后手的又是奇数台阶异或为0的状态
②当后手移动奇数台阶上的石子到偶数台阶上时,留给先手的奇数台阶异或非0,根据经典Nim游戏,先手总能找出一种方案使奇数台阶异或为0

因此无论后手如何移动,先手总能通过操作把奇数异或为0的情况留给后手,当奇数台阶全为0时,只留下偶数台阶上有石子。

因此如果先手时奇数台阶上的值的异或值为非0,则先手必胜,反之必败!

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int main() {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int n; cin >> n;
    int res = 0;
    for(int i = 1; i <= n; i++){
        int x; cin >> x;
        if(i & 1)
        res^=x;
    }
    if(res) cout << "Yes\n";
    else cout <<"No\n";
    return 0;
}

 集合-Nim游戏:

1.Mex运算:
设S表示一个非负整数集合.定义mex(S)为求出不属于集合S的最小非负整数运算
例如:S={0,1,2,4},那么mes(S)=3;

2.SG函数

  • 对于一个游戏状态 x,SG函数值 SG(x)表示从该状态出发,所有可能的后续状态的SG值所能达到的“最小非负整数”(Mex)。
  • 具体来说,若从状态 x通过合法操作可以到达的所有状态的SG值分别为 SG(y1),SG(y2),.......,SG(yk)那么 SG(x)就是一个不在这些SG值集合中的最小非负整数。

SG函数的性质:类似于经典的Nim游戏

  • 必败态(Losing Position):对于某个状态 x,如果 SG(x)=0那么当前处于该状态的玩家将无法避免失败(即在对方采取最优策略的情况下无论如何都会输)。
  • 必胜态(Winning Position):对于某个状态 x,如果 SG(x)\,\, \, !=\, \, \, 0,那么当前处于该状态的玩家有策略可以使对手进入必败态。也就是先手一定会胜利。

递归计算:

例如s = [2,5],x = 10时递归得到

 

初始状态:
  • f[x] 是用来存储每个x的SG值的数组,初始时f[x]的所有值都被设置为-1(表示尚未计算过)。
  • x = 10 是我们要计算的状态,s = [2, 5] 是可供选择的石子数。
计算 sg(10) 的过程:
  1. 调用 sg(10)

    • 首先检查 f[10],因为f[10] = -1,说明还没有计算过,所以继续计算。
    • 初始化集合 S
  2. 遍历 s[i]

    • s[0] = 2
      • 因为 10 >= 2,所以我们递归调用 sg(10 - 2) = sg(8)
    • s[1] = 5
      • 因为 10 >= 5,所以我们递归调用 sg(10 - 5) = sg(5)
  3. 递归调用 sg(8)

    • 首先检查 f[8],因为f[8] = -1,所以继续计算。
    • 初始化集合 S
    • 遍历 s[i]
      • s[0] = 2
        • 因为 8 >= 2,所以我们递归调用 sg(8 - 2) = sg(6)
      • s[1] = 5
        • 因为 8 >= 5,所以我们递归调用 sg(8 - 5) = sg(3)
  4. 递归调用 sg(6)

    • 首先检查 f[6],因为f[6] = -1,所以继续计算。
    • 初始化集合 S
    • 遍历 s[i]
      • s[0] = 2
        • 因为 6 >= 2,所以我们递归调用 sg(6 - 2) = sg(4)
      • s[1] = 5
        • 因为 6 >= 5,所以我们递归调用 sg(6 - 5) = sg(1)
  5. 递归调用 sg(4)

    • 首先检查 f[4],因为f[4] = -1,所以继续计算。
    • 初始化集合 S
    • 遍历 s[i]
      • s[0] = 2
        • 因为 4 >= 2,所以我们递归调用 sg(4 - 2) = sg(2)
      • s[1] = 5
        • 因为 4 < 5,所以跳过。
  6. 递归调用 sg(2)

    • 首先检查 f[2],因为f[2] = -1,所以继续计算。
    • 初始化集合 S
    • 遍历 s[i]
      • s[0] = 2
        • 因为 2 >= 2,所以我们递归调用 sg(2 - 2) = sg(0)
      • s[1] = 5
        • 因为 2 < 5,所以跳过。
  7. 递归调用 sg(0)

    • sg(0)是一个基本情况,因为没有石子可以取走,故f[0] = 0,返回 0
  8. 接下来如上继续.....
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 110, M = 10010;
int n,m;
int s[N],f[M];//s存储的是可供选择的石子数, f存储的是所有可能情况的SG值
int sg(int x){
    if(f[x] != -1) return f[x]; // 如果x的SG值已经计算过,直接返回
    set<int> S;
    //S是一个有序集合,用来存储当前状态的所有可能的下一步的SG值
    
    // 循环每一次可以选择拿走的石头数
    for(int i = 0; i < m; i++){
        // 递归计算x减去s[i]后的状态的SG值,并插入到集合S中
        if(x >= s[i]) S.insert(sg(x - s[i]));
    }
    
    //找到不存在的最小自然数
    for(int i = 0; ; i++){
        if(!S.count(i)) return f[x] = i;
    }
}

int main() {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin >> m;
    for(int i = 0; i < m; i++) cin >> s[i];
    cin >> n;
    memset(f,-1,sizeof f);
    f[0] = 0; //当x为0的时候sg函数返回0
    // 类似于经典的Nim游戏
    int res = 0;
    while(n--){
        int x; cin >> x;
        res ^= sg(x);
    }
    if(res) cout << "Yes\n";
    else cout <<"No\n";
    return 0;
}

拆分-Nim游戏

相比于集合-Nim,这里的每一堆可以变成小于原来那堆的任意大小的两堆 

即a[i]可以拆分成(b[i],b[j]),为了避免重复规定b[i]>=b[j]即:a[i]>b[i]>=b[j]

相当于一个局面拆分成了两个局面,由SG函数理论,多个独立局面的SG值,等于这些局面SG值的异或和。SG(i^j) = SG(i) ^SG(j)

因此需要存储的状态就是sg(b[i])^sg(b[j]),与集合-Nim的唯一区别

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 110, M = 10010;
int n,m;
int s[N],f[M];//s存储的是可供选择的石子数, f存储的是所有可能情况的SG值
int sg(int x){
    if(f[x] != -1) return f[x]; // 如果x的SG值已经计算过,直接返回
    set<int> S;//这里可以改为unordered_set<int> S
    //S是一个有序集合,用来存储当前状态的所有可能的下一步的SG值

    for(int i = 0; i < x; i++){
        for(int j = 0; j <= i; j++){
            S.insert(sg(i) ^ sg(j));
        }
    }

    //找到不存在的最小自然数
    for(int i = 0; ; i++){
        if(!S.count(i)) return f[x] = i;
    }
}

int main() {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin >> n;
    memset(f,-1,sizeof f);
    f[0] = 0;
    // 类似于经典的Nim游戏
    int res = 0;
    while(n--){
        int x; cin >> x;
        res ^= sg(x);
    }
     if(res) puts("Yes");
    else puts("No");
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2079299.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python机器学习】NLP分词——词的“情感”

目录 VADER&#xff1a;一个基于规则的情感分析器 朴素贝叶斯 无论NLP流水线中使用的是单个词、n-gram、词干还是词元作为词条&#xff0c;每个词条都包含了一些信息&#xff0c;这些信息中一个重要部分是词的情感&#xff0c;即一个词所唤起的总体感觉或感情。这种度量短语或…

XOR 已知明文攻击

在这篇博文中,我们详细展示了*针对 XOR 编码的*已知明文攻击是如何进行的,并使用自定义工具自动执行该攻击,以解密和提取 Cobalt Strike 信标的配置。如果您对理论不感兴趣,只对工具感兴趣,请直接跳到结论! 已知明文攻击 (KPA) 是一种密码分析方法,分析人员拥有消息的明文…

【设计模式-装饰】

定义 装饰模式是一种结构型设计模式&#xff0c;它允许在不改变对象自身的前提下动态地给对象添加职责&#xff08;功能&#xff09;。通过使用装饰模式&#xff0c;可以将对象的功能扩展变得更加灵活和可维护&#xff0c;同时避免了类继承的复杂性。 特点 动态扩展对象功能…

猫咪浮毛满天飞?希喂、IAM、352三款宠物空气净化器测试对比

我作为一名养宠三年的铲屎官&#xff0c;用过不少清理工具&#xff0c;可惜都效果不佳。经过朋友的推荐&#xff0c;我了解到宠物空气净化器这种产品&#xff0c;想要购入使用。在挑选时我发现&#xff0c;目前市面上宠物空气净化器品牌繁多&#xff0c;质量难辨。因此&#xf…

【iOS端】基于Uniapp跨平台接入即构RTC+相芯美颜

0 Uniapp平台接入完成iOS端的即构RTC相芯美颜 Uniapp最大优势是跨平台&#xff0c;前面介绍了如何在android中接入相芯美颜即构RTC&#xff0c;今天咱们把相同的代码接入到iOS中。按照惯例我们先看最终效果&#xff0c;欢迎大家评论讨论&#xff1a; 1 开发配置准备 iOS开发因…

YOLOv8目标检测部署RK3588全过程,附代码pt->onnx->rknn,附【详细代码】

目录 一、训练yolov8模型&#xff0c;得到最佳权重文件best.pt 二、pt转onnx,即best.pt->best11.onnx 1、对下载的YOLOv8代码修改 2、加入模型导出功能&#xff0c; 3、导出指令采用如下代码 三、ONNX转RKNN 四、RK3588部署 1、拷贝rknn文件到rk3588板子内 2、执行…

.NET6 多环境 在Windows IIS部署的应用场景

前言&#xff1a; 通常情况下 我们部署Web站点 需要用到 测试环境 和 正式环境 2个环境 Staging环境 或者其他环境 视 团队所处阶段、团队规模、质量要求、风险控制要求、第3方协议而定 1.我们把上一讲 IX.MultiEnvironment 这个项目发布到IIS中 2.IIS配置3个环境 我们重点…

MathType2025最新破解版补丁包+永久免费安装包win+mac系统

有一类笔记特别受欢迎&#xff0c;那就是“数学公式的排版”。这些笔记通常以图文并茂的方式&#xff0c;展示了如何使用各种工具来排版数学公式。其中&#xff0c;MathType 7 是最受欢迎的工具之一&#xff0c;它不仅功能强大、使用方便&#xff0c;还能让你轻松地制作出精美的…

Tailor:免费开源 AI 视频神器,创作者必备利器

目录 引言一、创新特性&#xff0c;引领视频编辑新潮流1. 智能人脸剪辑2. 精准语音剪辑3. 自动化口播生成4. 多样化字幕生成5. 一键式色彩生成 二、简单易用&#xff0c;新手也能快速上手1. 下载和安装2. 功能选择3. 操作流程 三、广泛应用&#xff0c;满足不同创作需求四、代码…

别让语法拖后腿:ChatGPT助你告别改稿噩梦!【建议收藏】

学术论文的撰写是研究成果传播的关键。清晰、准确、逻辑严密的表达对于学术论文的质量至关重要。人工智能技术的快速发展&#xff0c;尤其是ChatGPT 4.0的推出&#xff0c;为学术写作提供了新的辅助工具。本文将探讨如何有效利用ChatGPT 4.0进行论文润色。 ChatGPT&#xff1a…

线性代数:如何由AB=E 推出 BA=AB?

最近在二刷线性代数&#xff0c;在看逆矩阵定义的时候发现了这个问题。于是决定写一写&#xff0c;给出一种证明方式。 一、由逆矩阵的定义出发 这是我在mooc-山东大学-线性代数&#xff08;秦静老师&#xff09;第一章第十讲的ppt上截取的定义。 看到这个定义我就在想&#xf…

如何在Java中使用protobuf

写在前面 本文看下在Java中如何使用protofbuf。 1&#xff1a;介绍 1.1&#xff1a;什么是protobuf 是一种数据格式&#xff0c;同json&#xff0c;xml&#xff0c;等。但是一种二进制数据格式。 1.2&#xff1a;强在哪里&#xff1f;为啥要用&#xff1f; 小&#xff0c…

图新说-调整标绘线面的压盖顺序的两种方法

0.序 图新说作为一个三维可视化汇报工具&#xff0c;在公安消防领域常用于做态势标绘&#xff0c;应急救援方案&#xff0c;安保预案等。 如果撤离路线&#xff0c;或者行进路线【线对象】经过了水源地、危险区等【面对象】。如何确保线对象显示在面对象的上面&#xff0c;不被…

MyBatis中的占位符解析机制

深入理解 MyBatis 中的 #{} 占位符解析机制 在使用 MyBatis 进行数据库操作时&#xff0c;#{} 占位符是我们非常常用的一个特性。它能够将 Java 对象的属性值与 SQL 语句中的参数进行映射。在实际使用中&#xff0c;MyBatis 如何解析 #{} 占位符并获取对应的属性值呢&#xff…

如何实现低成本降噪?风扇噪声流体仿真解决方案

本文将说明工程师如何能够使用气动解决方案来模拟和降低一款小型发电机柜冷却风扇的噪音。ultraFluidX 的模拟结果将设备内部的流场和声场可视化&#xff0c;研究风扇和机柜内其他部件的相互作用&#xff0c;确认噪声源来自何处&#xff08;协助工程师采取有效的降噪措施&#…

Mybatis中的缓存

一&#xff0c;为什么要使用缓存 1&#xff0c;缓存的作用 缓存(cache&#xff09;的作用是为了减去数据库的压力&#xff0c;提高查询性能。 缓存实现的原理是 从数据库中查询出来的对象在使用完后不要销毁&#xff0c;而是存储在内存&#xff08;缓存&#xff09; 中&#…

zipkin启动发生报错 : Failed to start bean ‘armeriaServerGracefulShutdownLifecycle‘;

报错详情 : 在windows下启动zipkin的时候发生报错 : Failed to start bean ‘armeriaServerGracefulShutdownLifecycle’;nested exception is java.util.concurrent.CompletionException: java.lang.IllegalStateException: Armeria server failed to start解决 : 由于z…

SSM网上书店--附源码96453

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于网上书店当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了网上书店&#xff0c;它彻底改变了过去传统的管理方式…

安装cvxpy时遇到“subprocess-exited-with-error”的解决方式

尝试联邦学习时&#xff0c;遇到了这个问题&#xff0c;但实际上仔细看报错就能找到源头 ①更新cmake版本到3.17 参考此文即可更新 https://blog.csdn.net/why1249777255/article/details/138505546 【报错点中“Found CMake:…………”这一行&#xff0c;在不满足要求时会说…

信息学奥赛一本通编程启蒙(不断更新ing~)

可以作为c初学者的练习题&#xff0c;我会挑选有部分有代表意义的题目作为学生的课后作业&#xff0c;后面会在专栏中陆续更新题目解析&#xff0c;并附在这一篇文章的链接中 信息学奥赛一本通-编程启蒙&#xff08;C版&#xff09;在线评测系统 https://bas.ssoier.cn/index…