博弈问题学习笔记

在 OI 中常常有这样一类问题:两个人按照一定的规则轮流进行游戏,最后只能有一个人获胜。给定游戏的初始状态,求先手是否有必胜策略。这类问题我们统称博弈问题。

博弈问题通常有三类解决方法:dp 求解(SG 函数),数据结构维护,数学推导(结论),有时需要综合运用其中的几种方法。

一、一些定义与两个基本定理

定义:

  • 游戏的一些参数称为游戏的状态
  • 游戏的初始状态称为初态,最终能判定两人中谁获胜的状态叫做终态
  • 游戏从一个状态能转移到的另一个状态叫做这个状态的后继态
  • 存在先手必胜策略的状态叫做必胜态,不存在先手必胜策略的状态叫做必败态

两个基本定理:

  • 必胜态的所有后继态中存在至少一个必败态。
  • 必败态的所有后继态都是必胜态。

这两个定理读者自证不难。

二、dp 求解(SG 函数)

这是解决博弈问题最普适的一类方法。通过刚才的定义和基本定理,我们可以发现博弈游戏其实就是一系列状态的转移,类似 dp 的过程,所以我们有时会使用 dp 来解决博弈问题,或是为数学推导法打表找到一些周期性的规律,进行优化。

例题 1. 为美好的世界献上爆炎(version 1)

传送门:https://www.luogu.com.cn/problem/T467518

桌上有 \(n\) 枚硬币,两⼈轮流拿硬币。每次可以在区间 \([l, r]\) 中选择⼀个数字 \(x\) 然后拿走 \(x\) 枚硬币,若⼀⽅⽆法再拿取则输掉了游戏,由惠惠先⼿开始拿硬币。

惠惠和悠悠都是聪明的,现在惠惠想在游戏开始前,请你帮忙判断她是否能够必胜,若她可以必胜则会按照必胜策略和悠悠进⾏游戏,若不能必胜她就只好作弊来战胜悠悠了。

对于另 \(20\%\) 的数据,满足 \(n \leq 5000, t \leq 5000\)

题解:运用两个基本定理,我们可以写出这样的递推式:

\[dp_i=\left\{ \begin{array}{rcl} 0 & & {0 \le i < l}.\\ 1 & & {\exists j \in [\max(i - r, 0), i - l], dp_j = 0}.\\ 0 & & {\mathrm{otherwise}}.\\ \end{array} \right. \]

时间复杂度 \(O(n^2)\)

vector<int> dp(n + 1, 0); // 0 ... l - 1, 先手必败
for (int i = l; i <= n; i++) {for (int j = l; j <= r && j <= i; j++) {dp[i] |= !dp[i - j]; // 能转移到必败态,就是必胜态}
}
if (dp[n]) {cout << "yes\n";
} else {cout << "no\n";
}

例题 2. [AGC010F] Tree Game

传送门:https://www.luogu.com.cn/problem/AT_agc010_f

题解:我们钦定一开始放的位置为根结点进行 dp。首先考虑儿子都是叶子结点的节点,如果放在这个节点上,一定是先手在根,后手在某个叶子,如此来回,此时是先手掌握主动权。那么如果叶子的最小值比根小,就是必胜态。

再考虑更复杂的树,一定能规约到若干上一种情况。如果子树有先手必胜策略,那么一定不能放后手到那个节点上。否则规约到上一种情况,可以写出递推式:

\[dp_i=\left\{ \begin{array}{rcl} 1 & & {\exists j \in son_i, dp_j = 0 \land a_i > a_j}.\\ 0 & & {otherwise}.\\ \end{array} \right. \]

时间复杂度 \(O(n^2)\)

这题启发我们,类似 dp 的过程,我们分析博弈问题也可以从基本的子结构开始逐步扩展分析,这是非常实用的方法。

三、数据结构维护

通过数据结构,我们可以写出复杂的博弈递推,并且用数据结构进行优化。

例题 3. 为美好的世界献上爆炎(version 2)

在上一版的基础上,\(\sum n \le 10^5\)

使用数据结构维护 dp 即可,时间复杂度 \(O(n \log n)\)。这类问题本质是数据结构优化 dp,不多做展开。

例题 4. The Game

传送门:https://codeforces.com/problemset/problem/2062/E2

琪露诺和大妖星正在玩一个游戏,游戏树由 \(n\) 个节点组成,根节点为 \(1\)。第 \(i\) 个节点的值是 \(w_i\)。他们轮流玩游戏,琪露诺先手。

在每一轮中,假设对手在最后一轮中选择了 \(j\) ,玩家可以选择满足 \(w_i > w_j\) 的任何剩余节点 \(i\) ,并删除节点 \(i\) 的子树。特别的,琪露诺可以在第一轮中选择任意节点并删除其子树。第一个不能操作的玩家获胜,他们都希望获胜。

Simple Version:

找到琪露诺在第一轮可能选择的任意一个节点。不存在输出 \(0\)

题解:设琪露诺选择了节点 \(u\)。那么只要在 \(u\) 的子树外存在一个权值比 \(w_u\) 大的节点 \(v\),那么琪露诺不会直接输掉(这是 \(u\) 要满足的必要条件)。在这些不会输掉的点中选择权值最大的一个即可(因为换到后手后也不能选择直接输掉的点,但是这些点中权值最大的已经被选择了,所以后手就必败了)。

Hard Version:

找到琪露诺在第一轮可能选择的所有节点。不存在输出 \(0\)

题解:类似 Simple Version,我们要让后手完全不能进行操作(因为如果后手能进行操作,就能进行 Simple Version 中的构造使得先手输掉)。

设先手选择了节点 \(u\) 让后手无法选择,对于所有后手可能选择的节点 \(v\)(有 \(w_v > w_u\)),必须满足其中一个条件:

  • \(v\)\(u\) 的子树内;
  • \(v\) 不在 \(u\) 的子树内,但是除了 \(v\)\(u\) 的子树内,不存在任何权值比 \(w_v\) 大的节点 \(x\)

第一个条件是好进行处理的。对于第二个条件,可以转化为在 \(v\) 的子树外比权值比 \(w_v\) 大的节点 \(x\) 的最近公共祖先 \(l_v\)\(u\) 的子树内(或者干脆不存在这样的节点 \(x\))。

维护 \(l_v\)\(dfn\),配合 ST 表即可。

cin >> n, cnt = 0;
vector<array<int, 2>> node;
for (int i = 1; i <= n; i++) {cin >> a[i], G[i].clear();node.push_back({a[i], i});
}
for (int i = 1; i < n; i++) {cin >> u >> v;G[u].push_back(v);G[v].push_back(u);
}
dfs(1, 0);
vector<int> ans;
LCAFenwick<int> pre(n), suf(n);
MAXFenwick<int> pre_mx(n), suf_mx(n);
MINFenwick<int> pre_mn(n), suf_mn(n);
sort(node.begin(), node.end(), greater<>());
for (int l = 0, r = 0; l < n; l = r) {while (r < n && node[r][0] == node[l][0]) r++;for (int x = l; x < r; x++) { // calculate lcaconst int i = node[x][1];lca[i] = LCA(pre.query(dfn[i] - 1),suf.query(n + 1 - dfn[i] - siz[i]));const int mx = std::max(pre_mx.query(dfn[i] - 1),suf_mx.query(n + 1 - dfn[i] - siz[i]));const int mn = std::min(pre_mn.query(dfn[i] - 1),suf_mn.query(n + 1 - dfn[i] - siz[i]));if (lca[i] == 0) continue;if (dfn[i] <= mn && mx < dfn[i] + siz[i]) {ans.push_back(i);}}for (int x = l; x < r; x++) { // update info.const int i = node[x][1];pre.update(dfn[i], i);suf.update(n + 1 - dfn[i], i);if (lca[i] != 0) {pre_mx.update(dfn[i], dfn[lca[i]]);pre_mn.update(dfn[i], dfn[lca[i]]);suf_mx.update(n + 1 - dfn[i], dfn[lca[i]]);suf_mn.update(n + 1 - dfn[i], dfn[lca[i]]);}}
}

这也启示我们,有的博弈过程是很短暂的,可能只会进行一两轮。

三、数学推导

例题 5. 为美好的世界献上爆炎(version 3)

在上一版的基础上,\(n \le 10^9\)

题解:容易归纳证明有这样的周期性规律:\(dp_0 \sim dp_{l - 1} = 0, dp_{l} ~ dp_{r} = 1, dp{r + 1} \sim dp_{r + (r - l)} = 1, \dots\),取模判断即可。

例题 6. Resourceful Caterpillar Sequence

传送门:https://codeforces.com/problemset/problem/2053/E

题解:首先观察到后手可以撤销操作,所以游戏最多进行 \(2\) 轮,否则一定平局。

  1. 如果 \(p\)\(q\) 都是叶子节点,结果为平局。
  2. 如果 \(p\) 是叶子节点而 \(q\) 不是,Nora 获胜。
  3. 如果 \(q\) 是叶子节点而 \(p\) 不是,Aron 获胜。
  4. 如果 \(p\)\(q\) 都不是叶子节点:
  • \(k = 1\) 可以吗?当且仅当 \(p\) 与叶子节点相邻时,Nora 获胜。
  • \(k = 2\) 可以吗?当且仅当 \(p\) 不与叶子节点相邻,且 \(f(p, q)\) 与叶子节点相邻时,Aron 获胜。
  • 否则,结果为平局。

实现即可。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浏览器自动化与AI Agent结合项目browser-use初探

browser-use介绍 browser-use是将您的 AI 代理连接到浏览器的最简单方式。它通过提供一个强大且简单的接口来实现 AI 代理访问网站的自动化。 GitHub地址:https://github.com/browser-use/browser-use。目前已经获得了27.3k颗stars,2.7kforks,看得出来是一个比较热门的项目。…

自己如何在本地电脑从零搭建DeepSeek!手把手教学,快来看看! (建议收藏)

在人工智能飞速发展的今天,大语言模型的应用越来越广泛。DeepSeek 作为近期爆火的一款大语言模型,受到了众多开发者的青睐。 今天这篇内容,就来聊聊,如何在本地自己的电脑上部署DeepSeek。 1、哪些场景适合将大模型部署在自己电脑上? 先说结论: 虽说将大模型部署在自己的…

.NET Core + Vue3 个人博客后台系统更新啦~

基于vue-pure-admin框架搭建的博客后台系统介绍 本项目基于 vue-pure-admin 开发,原本博客后台使用StarBlog升级vue3版本搭建,鉴于被我改得烂七八糟,所以这次使用了新的架子搭建。 配套后端项目地址 更新之后后台地址:ZyPLJ/ZYBlog: 这是Personalblog的新版本库 老版本地址…

winform异步加载

1. 使用async和await关键字 首先,在你的方法前加上async关键字,然后在调用长时间运行的方法前使用await关键字。例如,如果你有一个长时间运行的方法LoadDataAsync(),你可以这样调用它:public async void LoadDataButton_Click(object sender, EventArgs e) {await Task.Ru…

我用abp做企业数字化应用

> 大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进。 这是一个系列文章,目前正在编写当中,敬请期待……希望以上分享对你有所帮助,感谢您的捧场。微信: 张飞洪[厦门] 我的视频:ABP vNext视频系…

如何实现多节点数据同步,提高传输可靠性和整体效率?

多节点数据同步是指在分布式系统中,将多个节点或系统之间的数据保持一致,使得它们能够共享相同的数据状态,从而实现数据的高可用性、冗余性和一致性,确保在数据发生变化时,所有相关节点都能及时感知并同步这些变化。多节点数据同步在多个领域和场景中都有广泛的应用,比如…

5. Docker 本地镜像发布到阿里云

5. Docker 本地镜像发布到阿里云 @目录5. Docker 本地镜像发布到阿里云1. 本地镜像发布到阿里云流程最后:1. 本地镜像发布到阿里云流程镜像的生成方法: 基于当前容器创建一个新的镜像,新功能增强 docker commit [OPTIONS] 容器ID [REPOSITORY[:TAG]]OPTIONS说明: -a :提交的…

清华博士后的DeepSeek使用手册,104页,真的是太厉害了!(免费领取源文件)

《DeepSeek从入门到精通2025》是由清华大学元宇宙文化实验室的余梦珑博士后及其团队撰写。文档的核心内容围绕DeepSeek的技术特点、应用场景、使用方法以及如何通过提示语设计提升AI使用效率等方面展开,帮助用户从入门到精通DeepSeek的使用。 以前我看了很多教程,都感觉特别花…

【一文详解】企业不可错过的一款内外网文件交换系统

一、内外网文件交换系统对企业的意义 内外网文件交换系统对于企业的价值和意义非常重要,尤其在当前数字化转型和信息化管理日益推进的背景下。以下是其主要价值和意义: 1、提升工作效率 内外网文件交换系统能够高效地处理跨部门、跨地域的文件传输需求,减少了传统方式中人工…

VMware NSX Advanced Load Balancer (NSX ALB) 30.1.2 - 多云负载均衡平台

VMware NSX Advanced Load Balancer (NSX ALB) 30.1.2 - 多云负载均衡平台VMware NSX Advanced Load Balancer (NSX ALB) 30.1.2 - 多云负载均衡平台 应用交付:多云负载均衡、Web 应用防火墙和容器 Ingress 服务 请访问原文链接:https://sysin.org/blog/vmware-nsx-alb-30/ 查…

Symantec Endpoint Protection 14.3 RU10 v14.3.12154.10000 下载

Symantec Endpoint Protection 14.3 RU10 v14.3.12154.10000 下载Symantec Endpoint Protection 14.3 RU10 v14.3.12154.10000 下载 Broadcom | SEP | SEPM | 简体中文版 | 繁体中文版 | 英文版 请访问原文链接:https://sysin.org/blog/sep-14/ 查看最新版。原创作品,转载请保…

动态编译一个新的 NativeApi 类

要动态编译一个新的 NativeApi 类,可以按照以下步骤进行:创建一个新的 NativeApi 类。 在 NativeApi 类中定义所需的方法和属性。 在 MainPage 中实例化并使用新的 NativeApi 类。using MauiPlus; using System.Reflection.Emit; using System.Reflection;namespace MauiPlus…