博弈论-acwing893.集合-Nim游戏
补充知识
有向图游戏
给定一个有向无环图,图中有一个唯一的起点,在起点上放有一枚棋子。两名玩家交替地把这枚棋子沿着有向边方向移动,每次可以移动一步,无法移动者判负。该游戏被称为有向图游戏。任何一个公平组合游戏都可以转化为有向图游戏。具体方法是,把每个局面看成图中的一个结点,并且从每个局面向沿着合法行动能够到达下一个局面连有向边。
这个题每一堆石子都可以看做成一个有向图
Mex运算
设S表示一个非负整数集合。定义为求不出属于集合S的最小非负整数的运算,即:,x属于自然数,且x不属于S
SG函数
在有向图游戏中,对于每个节点x,设从x除法共有k条有向边,分别到达结点,定义为x的后继结点的函数值构成的集合再执行运算的结果,即:。
特别的,整个有向图游戏G的SG函数值被定义为有向图游戏起点s的SG函数值,即:
SG定理(有向图游戏的和)
设是m个有向图游戏。定义有向图游戏G,它的行动规则是任选某个有向图游戏,并在上行动一步。G被称为有向图游戏的和。
有向图游戏的和SG函数在数值上等于它所包含的各个子游戏SG函数的异或和,即:
存在结论:
对于n个图,如果,则先手必胜,否则先手必败
acwing893.集合-Nim游戏
思路
表示的是每一堆石子有多少个,将每一个看做一张有向图
例如
看h[1]这张有向图:

(ps:注意求SG函数需要mex()函数求,看其定义不要搞乱了)
#include<iostream>
#include<unordered_set>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100, M = 10010;
int n,m;
int f[M],s[N]; //f表示可能出现过的sg函数值,s表示可选正整数的集合
int sg(int x)
{
if(f[x] != -1) return f[x]; // 如果算出来过sg(x)就直接返回f[x]
unordered_set<int> S; // 用来存储该节点下一步的节点他们的sg函数值
for(int i = 0; i < n; i ++)
{
int sum = s[i];
if(x >= sum) S.insert(sg(x - sum)); // 如果存在下一步,将下一步节点sg函数值存入
}
// mex操作
for(int i = 0;;i ++)
{
if(!S.count(i)) return f[x] = i;
}
}
int main()
{
cin >> n ;
for(int i = 0; i < n; i ++) cin >> s[i];
cin >> m;
memset(f,-1,sizeof(f));
int res = 0;
for(int i = 0; i < m; i ++)
{
int x; // x表示这一堆石子的数量
cin >> x;
res ^= sg(x);
}
if(res) puts("Yes");
else puts("No");
return 0;
}
rds_blogs
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!