AcWing 891:Nim游戏 ← SG函数 + Nim博弈

【题目来源】
https://www.acwing.com/problem/content/893/

【题目描述】
给定 n 堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。

【输入格式】
第一行包含整数 n。
第二行包含 n 个数字,其中第 i 个数字表示第 i 堆石子的数量。

【输出格式】
如果先手方必胜,则输出 Yes。
否则,输出 No。

【输入样例】
2
2 3

【输出样例】
Yes

【数据范围】
1≤n≤10^5,
1≤每堆石子数≤10^9

【算法分析】
Nim 博弈定理 :对于任意的 {a1, a2, a3, ..., an},++若++ ++S=a1⊕a2⊕a3⊕⋯⊕an++ ++的值不等于 0,先手必胜++ ,记为 N-position(先手必胜态)。++若 S=a1⊕a2⊕a3⊕⋯⊕an 的值等于 0,先手必败++ ,记为 P-position(先手必败态)。

● 标准 Nim 堆的 SG 函数值
对于标准 Nim 的单堆石子,状态 x 表示堆内有 x 枚石子。
取走任意非零(1~x)枚石子,可得状态 x 的后继集合为 {0, 1, ..., x-1}。
故,sg(x)=mex{sg(0), sg(1), ..., sg(x-1)}。

cpp 复制代码
x=1:后继为 1-1=0,后继 SG 集合为 {SG(0)}={0},则得 SG(1)=mex{0}=1
x=2:后继为 2-1=1,2-2=0,后继 SG 集合为 {SG(1),SG(0)}={1,0},则得 SG(2)=mex{0,1}=2
x=3:后继为 3-1=2,3-2=1,3-3=0,后继 SG 集合为 {SG(2),SG(1),SG(0)}={2,1,0},则得 SG(3)=mex{0,1,2}=3
x=4:后继为 4-1=3,4-2=2,4-3=1,4-4=0,后继 SG 集合为 {SG(3),SG(2),SG(1),SG(0)}={3,2,1,0},则得 SG(4)=mex{0,1,2,3}=4
......
猜想一般式:SG(x)=x。

故数学归纳可得,标准 Nim 堆的 SG 函数为:sg(x)=x。

【算法代码一:SG函数写法】

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int SG(int x) {
    return x;
}

int main() {
    int n,t=0;
    cin>>n;
    while(n--) {
        int x;
        cin>>x;
        t^=SG(x);
    }
    if(t==0) cout<<"No";
    else cout<<"Yes";

    return 0;
}

/*
in:
2
2 3

out:
Yes
*/

【算法代码二:非SG函数写法】

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n,t=0;
    cin>>n;
    while(n--) {
        int x;
        cin>>x;
        t^=x;
    }
    if(t==0) cout<<"No";
    else cout<<"Yes";

    return 0;
}

/*
in:
2
2 3

out:
Yes
*/

【参考文献】

https://blog.csdn.net/hnjzsyjyj/article/details/158704426

https://www.acwing.com/file_system/file/content/whole/index/content/12084580/

相关推荐
_OP_CHEN6 个月前
【算法基础篇】(六十一)SG 函数通关指南:博弈论通用解法,从原理到实战秒杀各类 ICG 游戏
算法·蓝桥杯·c/c++·博弈论·acm/icpc·sg函数·有向图游戏
_OP_CHEN6 个月前
【算法基础篇】(六十)Nim 博弈超全解析:从基础原理到经典变种,玩转多堆取石子问题
算法·蓝桥杯·c/c++·博弈论·算法竞赛·acm、icpc·nim博弈
Ayanami_Reii9 个月前
基础数学算法-移棋子游戏
数学·算法·游戏·博弈论·sg函数