Nim游戏博弈论

news2024/11/14 20:17:46

【模板】nim 游戏

题目描述

https://www.luogu.com.cn/problem/P2197

甲,乙两个人玩 nim 取石子游戏。

nim 游戏的规则是这样的:地上有 n n n 堆石子(每堆石子数量小于 1 0 4 10^4 104),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取完,不能不取。每次只能从一堆里取。最后没石子可取的人就输了。假如甲是先手,且告诉你这 n n n 堆石子的数量,他想知道是否存在先手必胜的策略。

输入格式

本题有多组测试数据。

第一行一个整数 T T T T ≤ 10 T\le10 T10),表示有 T T T 组数据

接下来每两行是一组数据,第一行一个整数 n n n,表示有 n n n 堆石子, n ≤ 1 0 4 n\le10^4 n104

第二行有 n n n 个数,表示每一堆石子的数量.

输出格式

T T T 行,每行表示如果对于这组数据存在先手必胜策略则输出 Yes,否则输出 No

样例 #1

样例输入 #1

2
2
1 1
2
1 0

样例输出 #1

No
Yes

思路

如果初态为必胜态 a 1 ∧ a 2 ∧ a 3 . . . ∧ a n ! = 0 a_1 \land a_2 \land a_3 .. . \land a_n!=0 a1a2a3...an!=0,则先手必胜。

如果初态为必败态,即上式结果为0,则先手必败

证明:

  1. 必胜态一定可以给对手留下一个必败态

s = a 1 ∧ . . . ∧ a n ! = 0 s=a_1 \land ... \land a_n!=0 s=a1...an!=0,设s的二进制为1的最高位为k

那么一定有奇数个 a i a_i ai的二进制位的第k位为1,我们使用 a i ∧ s a_i\land s ais替换 a i a_i ai,那么

a 1 ∧ . . . ∧ a i ∧ s . . . ∧ a n = s ∧ s = 0 a_1 \land ... \land a_i \land s... \land a_n=s \land s=0 a1...ais...an=ss=0

同时可以保证 a i ∧ s < a i a_i \land s<a_i ais<ai

  1. 必败态一定给对手留下必胜态

因为必败态 a 1 ∧ a 2 . . . ∧ a n = 0 a_1 \land a_2 ... \land a_n=0 a1a2...an=0,看二进制位上面1的个数,相同位上面1的个数一定是偶数个,因此无论减少哪个数,异或和都不为0了,即给对手一个必胜态

代码

#include <bits/stdc++.h>

#define int long long
using namespace std;


signed main() {
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    int t;
    cin >> t;
    while (t--) {
        int n, x;
        cin >> n;
        int res = 0;
        while (n--) {
            cin >> x;
            res ^= x;
        }
        cout << (res ? "Yes" : "No") << endl;
    }
    return 0;
}

取火柴游戏

题目描述

https://www.luogu.com.cn/problem/P1247

输入 k k k k k k 个整数 n 1 , n 2 , ⋯   , n k n_1,n_2,\cdots,n_k n1,n2,,nk,表示有 k k k 堆火柴棒,第 i i i 堆火柴棒的根数为 n i n_i ni;接着便是你和计算机取火柴棒的对弈游戏。取的规则如下:每次可以从一堆中取走若干根火柴,也可以一堆全部取走,但不允许跨堆取,也不允许不取。

谁取走最后一根火柴为胜利者。

例如: k = 2 k=2 k=2 n 1 = n 2 = 2 n_1=n_2=2 n1=n2=2,A 代表你,P 代表计算机,若决定 A 先取:

  • A: ( 2 , 2 ) → ( 1 , 2 ) (2,2) \rightarrow (1,2) (2,2)(1,2),即从第一堆中取一根。
  • P: ( 1 , 2 ) → ( 1 , 1 ) (1,2) \rightarrow (1,1) (1,2)(1,1),即从第二堆中取一根。
  • A: ( 1 , 1 ) → ( 1 , 0 ) (1,1) \rightarrow (1,0) (1,1)(1,0)
  • P: ( 1 , 0 ) → ( 0 , 0 ) (1,0) \rightarrow (0,0) (1,0)(0,0)。P 胜利。

如果决定 A A A 后取:

  • P: ( 2 , 2 ) → ( 2 , 0 ) (2,2) \rightarrow (2,0) (2,2)(2,0)
  • A: ( 2 , 0 ) → ( 0 , 0 ) (2,0) \rightarrow (0,0) (2,0)(0,0)。A 胜利。

又如 k = 3 k=3 k=3 n 1 = 1 n_1=1 n1=1 n 2 = 2 n_2=2 n2=2 n 3 = 3 n_3=3 n3=3 A A A 决定后取:

  • P: ( 1 , 2 , 3 ) → ( 0 , 2 , 3 ) (1,2,3) \rightarrow (0,2,3) (1,2,3)(0,2,3)
  • A: ( 0 , 2 , 3 ) → ( 0 , 2 , 2 ) (0,2,3) \rightarrow (0,2,2) (0,2,3)(0,2,2)
  • A 已将游戏归结为 ( 2 , 2 ) (2,2) (2,2) 的情况,不管 P 如何取 A 都必胜。

编一个程序,在给出初始状态之后,判断是先取必胜还是先取必败,如果是先取必胜,请输出第一次该如何取。如果是先取必败,则输出 lose

输入格式

第一行,一个正整数 k k k

第二行, k k k 个整数 n 1 , n 2 , ⋯   , n k n_1,n_2,\cdots,n_k n1,n2,,nk

输出格式

如果是先取必胜,请在第一行输出两个整数 a , b a,b a,b,表示第一次从第 b b b 堆取出 a a a 个。第二行为第一次取火柴后的状态。如果有多种答案,则输出 ⟨ b , a ⟩ \lang b,a\rang b,a 字典序最小的答案( 即 b b b 最小的前提下,使 a a a 最小)。

如果是先取必败,则输出 lose

样例 #1

样例输入 #1

3
3 6 9

样例输出 #1

4 3
3 6 5

样例 #2

样例输入 #2

4
15 22 19 10

样例输出 #2

lose

提示

数据范围及约定

对于全部数据, k ≤ 500000 k \le 500000 k500000 n i ≤ 1 0 9 n_i \le 10^9 ni109

思路

与上一题的Nim游戏一样,这里需要特殊输出第一次拿走的数量

代码

#include <bits/stdc++.h>

#define int long long
using namespace std;


signed main() {
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    int n;
    cin >> n;
    vector<int> a(n + 1);
    int res = 0;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        res ^= a[i];
    }
    if (!res) {
        cout << "lose";
    } else {
        for (int i = 1; i <= n; i++) {
            if ((a[i] ^ res) < a[i]) {
                cout << (a[i] - (a[i] ^ res)) << " " << i << endl;
                a[i] = a[i] ^ res;
                break;
            }
        }
        for (int i = 1; i <= n; ++i) {
            cout << a[i] << " \n"[i == n];
        }
    }


    return 0;
}

取数游戏 II

题目描述

有一个取数的游戏。初始时,给出一个环,环上的每条边上都有一个非负整数。这些整数中至少有一个 0 0 0。然后,将一枚硬币放在环上的一个节点上。两个玩家就是以这个放硬币的节点为起点开始这个游戏,两人轮流取数,取数的规则如下:

  1. 选择硬币左边或者右边的一条边,并且边上的数非 0 0 0

  2. 将这条边上的数减至任意一个非负整数(至少要有所减小);

  3. 将硬币移至边的另一端。

如果轮到一个玩家走,这时硬币左右两边的边上的数值都是 0 0 0,那么这个玩家就输了。

如下图,描述的是 Alice 和 Bob 两人的对弈过程(其中黑色节点表示硬币所在节点)。

各图的结果为:

A \text{A} A:Alice 胜; B \text{B} B:Bob 胜; C \text{C} C:Alice 胜; D \text{D} D:Bob 胜。

D \text{D} D 中,轮到 Bob 走时,硬币两边的边上都是 0 0 0,所以 Alice 获胜。

现在,你的任务就是根据给出的环、边上的数值以及起点(硬币所在位置),判断先走方是否有必胜的策略。

输入格式

第一行一个整数 N N N ( N ≤ 20 ) (N \leq 20) (N20),表示环上的节点数。

第二行 N N N 个数,数值不超过 30 30 30,依次表示 N N N 条边上的数值。硬币的起始位置在第一条边与最后一条边之间的节点上。

输出格式

仅一行。若存在必胜策略,则输出 YES,否则输出 NO

样例 #1

样例输入 #1

4
2 5 3 0

样例输出 #1

YES

样例 #2

样例输入 #2

3
0 0 0

样例输出 #2

NO

思路

要么一直顺时针走,要么一直逆时针走,每次走的时候一定是把这条边减小为0,否则对手可以反过来走,让你变成失败。

找第一个为0的位置,看初始点到这个点要走多少次,奇数次则先手获胜。

代码

#include <bits/stdc++.h>

#define int long long
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
#define IOS cin.tie(0), cout.tie(0), ios::sync_with_stdio(false);
#define cxk 1
#define debug(s, x) if (cxk) cout << "#debug:(" << s << ")=" << x << endl;
using namespace std;

void solve() {
    int n;
    cin >> n;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    int cnt1 = 0, cnt2 = 0;
    for (int i = 1; i <= n && a[i]; i++, cnt1++);
    for (int i = n; i >= 1 && a[i]; i--, cnt2++);
    if (cnt1 & 1 || cnt2 & 1) {
        yes
    } else {
        no
    }
}

signed main() {
    IOS
#ifndef ONLINE_JUDGE
    freopen("../test.in", "r", stdin);
    freopen("../test.out", "w", stdout);
#endif
    int _ = 1;
    while (_--) solve();
    return 0;
}

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

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

相关文章

管理后台低代码PaaS平台源码:点击鼠标,就能编程

低代码平台源码10大核心功能:1建模引擎 、2 移动引擎 、3,流程引擎 5.报表引擎、6安全引擎、 7 API引擎 、8.应用集成引擎、 9.代码引擎、 10.公式引擎。 一、低代码开发特色 1.低代码开发&#xff1a;管理后台提供了一系列易于使用的低代码开发工具&#xff0c;使企业可以快速…

CSPM难度大吗?对比pmp怎么样?

CSPM证书是刚出来的&#xff0c;难度不会很大&#xff0c;大家都知道 PMP 证书是从国外引进的&#xff0c;近几年很热门&#xff0c;持证人数已经高达 90 余万了&#xff0c;但是目前我们和老美关系大家有目共睹&#xff0c;一直推国际标准和美国标准感觉有点奇怪。 现在新出台…

React Flow

// 创建项目 npm create vitelatest my-react-flow-app -- --template react // 安装插件 npm install reactflow // 运行项目 npm run dev 1、App.jsx import { useCallback, useState } from react; import ReactFlow, {addEdge,ReactFlowProvider,MiniMap,Controls,useNode…

适用于虚拟环境的免费企业备份软件

多年来&#xff0c;许多行业严重依赖物理服务器提供计算资源——你可以想象到巨大的服务器机房和笨重的服务器的场景。 然而&#xff0c;随着业务快速增长&#xff0c;许多组织发现物理服务器已经无法有效利用计算资源。因此&#xff0c;为了节省成本&#xff0c;引入了虚拟服…

STL中 vector常见函数用法和迭代器失效的解决方案【C++】

文章目录 size && capacityreserveresizeempty迭代器begin和end push_back &&pop_backinsert && erasefindswap[ ]范围for遍历vector迭代器失效问题 size && capacity #include <iostream> #include <vector> using namespace st…

一文搞懂如何在群晖NAS中使用cpolar实现【内网穿透】

文章目录 1.1前言2.如何在群晖nas中使用cpolar内网穿透2.1第一步——进入套件中心2.2第二步——管理cpolar套件2.3第三步——建立专属的数据隧道2.4 第四步——查看本地数据隧道状态是否激活 3.结语 1.1前言 今天&#xff0c;我们来为大家介绍&#xff0c;如何在群晖系统中&am…

设计模式-命令模式在Java中的使用示例-桌面程序自定义功能键

场景 欲开发一个桌面版应用程序&#xff0c;该应用程序为用户提供了一系列自定义功能键&#xff0c;用户可以通过这些功能键来实现一些快捷操作。 用户可以将功能键和相应功能绑定在一起&#xff0c;还可以根据需要来修改功能键的设置&#xff0c;而且系统在未来可能还会增加…

做外贸工厂跳过我联系了客户

在我十多年外贸创业历程里&#xff0c;遇过不少想跳过我直接和客户联系的供应商。 譬如给客户发邮件&#xff0c;悄咪咪将我从抄送里删掉。又或者偷偷将名片塞在货柜里&#xff0c;期望客户一开箱就能看到。 然而这么多年过去&#xff0c;一次让他们得逞的机会都没有。每一次…

C++多线程编程(第三章 案例1,使用互斥锁+ list模拟线程通信)

主线程和子线程进行list通信&#xff0c;要用到互斥锁&#xff0c;避免同时操作 1、封装线程基类XThread控制线程启动和停止&#xff1b; 2、模拟消息服务器线程&#xff0c;接收字符串消息&#xff0c;并模拟处理&#xff1b; 3、通过Unique_lock和mutex互斥方位list 消息队列…

【力扣每日一题】2023.7.28 并行课程3

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们课程表以及每门课需要学习的时间&#xff0c;我们可以同时学任意数量的课程&#xff0c;但是学习的条件是先修课程都已经学完了…

【雕爷学编程】MicroPython动手做(02)——尝试搭建K210开发板的IDE环境6

#尝试搭建K210的Micropython开发环境&#xff08;Win10&#xff09; #实验程序之六&#xff1a;测试Microphone阵列算法 #尝试搭建K210的Micropython开发环境&#xff08;Win10&#xff09; #实验程序之六&#xff1a;测试Microphone阵列算法from Maix import MIC_ARRAY as mi…

MySQL运维:从全备sql文件中提取指定表的数据并恢复

目录 一、运行环境 二、需求说明 三、思路分析 五、具体方案 六、恢复表数据 一、运行环境 系统&#xff1a;CentOS7.3 数据库&#xff1a;MySQL 8.0.21 二、需求说明 线上有个表的数据被误操作了很多&#xff0c;无法通过bin-log进行具体的恢复。所以当前我们需要从全…

Spring Boot 应用程序生命周期扩展点妙用

文章目录 前言1. 应用程序生命周期扩展点2. 使用场景示例2.1 SpringApplicationRunListener2.2 ApplicationEnvironmentPreparedEvent2.3 ApplicationPreparedEvent2.4 ApplicationStartedEvent2.5 ApplicationReadyEvent2.6 ApplicationFailedEvent2.7 ApplicationRunner 3. 参…

产品能力|AIRIOT可视化组态引擎如何应用于物联业务场景中

在物联网的业务应用场景中&#xff0c;可视化组态是一个必不可少的功能需求。不同的行业场景&#xff0c;都需要将物联设备采集的数据和业务场景状态进行直观的可视化展示&#xff0c;供使用者进行分析或决策。如工艺流程用能监测、3D场景构建、能耗趋势场景报警联动、重点设备…

RAD-NeRF模型

问题1&#xff1a; 添加在以下的参数里添加bin_size0 问题2&#xff1a; 更行GLIBC_2.29_glibc_2_29.so_xihuanyuye的博客-CSDN博客

如何使用Crank给我们的类库做基准测试

背景 当我们写了一个类库提供给别人使用时&#xff0c;我们可能会对它做一些基准测试来测试一下它的性能指标&#xff0c;好比内存分配等。 在 .NET 的世界中&#xff0c;用 BenchmarkDotNet 来做这件事是非常不错的选择&#xff0c;我们只要写少量的代码就可以在本地运行基准…

【小白必看】Python爬取NBA球员数据示例

文章目录 前言导入需要的库和模块设置请求头和请求地址发送HTTP请求并获取响应处理响应结果解析数据将结果保存到文件完整代码详细解析 运行效果结束语 前言 使用 Python 爬取 NBA 球员数据的示例代码。通过发送 HTTP 请求&#xff0c;解析 HTML 页面&#xff0c;然后提取出需要…

imgcat命令行查看图片

背景 昨天在哔哩哔哩上看到了mac控制台工具imgcat 可以实现在控制台查看图片&#xff0c;我觉得太酷炫了&#xff01;于是手动的安利一下。 下载工具 curl "https://iterm2.com/utilities/imgcat" > imgcat执行权限 chmod x imgcat第一次使用 ./imgcat ~/img…

RocketMQ发送消息还有这种坑?遇到SYSTEM_BUSY不重试?

这里是weihubeats,觉得文章不错可以关注公众号小奏技术&#xff0c;文章首发。拒绝营销号&#xff0c;拒绝标题党 RocketMQ版本 5.1.0 背景 最近线上的RocketMQ集群遇到了如下问题&#xff0c;业务方的小伙伴反馈问题&#xff0c;说出现了 MQBrokerException&#xff1a;CO…

C++数据结构笔记(10)递归实现二叉树的三序遍历

对于三种遍历方式来说&#xff0c;均为先左后右&#xff01;区别在于根结点的位置顺序 先序遍历&#xff1a;根——左——右 中序遍历&#xff1a;左——根——右 后序遍历&#xff1a;左——右——根 &#xff08;所谓先中后的顺序&#xff0c;是指根结点D先于子树还是后于…