Nim游戏博弈论

【模板】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_JUDGEfreopen("test.in", "r", stdin);freopen("test.out", "w", stdout);
#endifint 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_JUDGEfreopen("test.in", "r", stdin);freopen("test.out", "w", stdout);
#endifint 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_JUDGEfreopen("../test.in", "r", stdin);freopen("../test.out", "w", stdout);
#endifint _ = 1;while (_--) solve();return 0;
}

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

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

相关文章

ISO 7637-2 5a/5b抛负载测试保护用TVS二极管,如何选型号?

在国际标准ISO 16750-2颁布之前&#xff0c;全球各大汽车零部件制造商一直采用的是ISO 7637-2标准。ISO 16750-2国际标准发行之后&#xff0c;汽车抛负载浪涌测试中ISO 7637-2 5A和5B测试标准被ISO 16750-2测试标准取代。查看ISO 16750-2和ISO 7637-2国际标准文档资料对比会发现…

13个ChatGPT类实用AI工具汇总

在ChatGPT爆火后&#xff0c;各种工具如同雨后春笋一般层出不穷。以下汇总了13种ChatGPT类实用工具&#xff0c;可以帮助学习、教学和科研。 01 / ChatGPT for google/ 一个浏览器插件&#xff0c;可搭配现有的搜索引擎来使用 最大化搜索效率&#xff0c;对搜索体验的提升相…

多线程(JavaEE初阶系列6)

目录 前言&#xff1a; 1.什么是线程池 2.标准库中的线程池 3.实现线程池 结束语&#xff1a; 前言&#xff1a; 在上一节中小编带着大家了解了一下Java标准库中的定时器的使用方式并给大家实现了一下&#xff0c;那么这节中小编将分享一下多线程中的线程池。给大家讲解一…

NoSQL-Redis集群

NoSQL-Redis集群 一、集群&#xff1a;1.单点Redis带来的问题&#xff1a;2.解决&#xff1a;3.集群的介绍&#xff1a;4.集群的优势&#xff1a;5.集群的实现方式&#xff1a; 二、集群的模式&#xff1a;1.类型&#xff1a;2.主从复制&#xff1a; 三、搭建主从复制&#xff…

在CentOS 7上挂载硬盘到系统的步骤及操作

目录 1&#xff1a;查询未挂载硬盘2&#xff1a;创建挂载目录3&#xff1a;检查磁盘是否被分区4&#xff1a;格式化硬盘5&#xff1a;挂载目录6&#xff1a;检查挂载状态7&#xff1a;设置开机自动挂载总结&#xff1a; 本文介绍了在CentOS 7上挂载硬盘到系统的详细步骤。通过确…

代码随想录算法训练营第二十八天 | Leetcode随机抽题检测

Leetcode随机抽题检测--使用题库&#xff1a;Leetcode热题100 1 两数之和未看解答自己编写的青春版重点题解的代码日后再次复习重新写 49 字母异位词分组未看解答自己编写的青春版重点题解的代码日后再次复习重新写 128 最长连续序列未看解答自己编写的青春版重点关于 left 和 …

C语言每日一题:12《数据结构》相交链表。

题目&#xff1a; 题目链接 思路一&#xff1a; 1.如果最后一个节点相同说明一定有交点。 2.使用两个循环获取一下长度&#xff0c;同时可以获取到尾节点。 3。注意初始化lenA和lenB为1&#xff0c;判断下一个节点是空是可以保留尾节点的。长度会少一个&#xff0c;尾节点没有…

根据前序和中序遍历序列构造二叉树 (递归+迭代两种方法实现)

给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 输入: preorder [3,9,20,15,7], inorder [9,3,15,20,7] 输出: [3,9,20,null,null,15,7]源代码如下…

【虚拟数字人】SadTalker简易部署教程

视频教程在这里&#xff1a; sadtalker数字人创建简易教程 项目基于SadTalkers实现视频唇形合成的Wav2lip。通过以视频文件方式进行语音驱动生成唇形&#xff0c;设置面部区域可配置的增强方式进行合成唇形&#xff08;人脸&#xff09;区域画面增强&#xff0c;提高生成唇形的…

修改conda环境缓存默认路径

前言&#xff1a;conda环境占用的内存太大了&#xff0c;每次建立一个新的虚拟环境都要加5个G差不多。所以想要修改默认的路径 问题1&#xff1a;找不到.condarc文件夹 创建condarc文件命令 conda config --add channels r 修改conda环境缓存默认路径 打开.condarc 添加 en…

xinput1_4.dll丢失怎么办?这几个方法都能解决

xinput1_4.dll是一个动态链接库文件&#xff08;DLL&#xff09;&#xff0c;它是Microsoft DirectX的一部分&#xff0c;用于处理游戏控制器输入。当你的电脑提示xinput1_4.dll文件丢失时&#xff0c;意味着与这个文件相关的游戏或应用程序无法正常运行。 当你的电脑提示xinp…

iPhone 8 Plus透明屏应用范围详解

iPhone 8 Plus是苹果公司于2017年推出的一款智能手机&#xff0c;它采用了全新的玻璃机身设计&#xff0c;支持无线充电&#xff0c;并且搭载了更强大的A11仿生芯片。 而透明屏则是一种新型的屏幕技术&#xff0c;可以使手机屏幕呈现出透明的效果。 透明屏是一种将屏幕背后的元…

基于深度学习的裂纹图像分类研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

11、springboot项目启动时对容器中的bean进行延迟初始化

springboot项目启动时对容器中的bean进行延迟初始化 预初始化&#xff1a; Spring Boot在启动应用时&#xff0c;会启动Spring容器&#xff0c;当启动Spring容器时&#xff0c;Spring会自动初始化容器中所有的singleton Bean——这是默认行为 预初始化的好处&#xff1a; 1、项…

MATLAB编程实践12、13

生命游戏 游戏的宇宙是无限可扩展的二维矩形网格&#xff0c;群体是那些标注为存活的网格的集合。群体可以依照称为代的离散时间步距进化。在每一步中&#xff0c;每个网格的命运由它周围最近的8个网格邻居的活度决定&#xff0c;规则如下&#xff1a; 如果一个存活的网格有两个…

dubbo-helloworld示例

1、工程架构 2、创建模块 &#xff08;1&#xff09;创建父工程,引入公共依赖 pom.xml依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></depende…

图像处理库(Opencv, Matplotlib, PIL)以及三者之间的转换

文章目录 1. Opencv2. Matplotlib3. PIL4. 三者的区别和相互转换5. Torchvision 中的相关转换库5.1 ToPILImage([mode])5.2 ToTensor5.3 PILToTensor 1. Opencv opencv的基本图像类型可以和numpy数组相互转化&#xff0c;因此可以直接调用torch.from_numpy(img) 将图像转换成t…

SQL-事务

set autocommit 0; select * from acount where name 嘉宝 && acount.money > 1000; update acount set money money - 1000 where name 嘉宝; update acount set money money 1000 where name 煎包; commit ; 脏读;当有两个事务使用同一数据库时&#xff0c…

SQL SERVER使用发布订阅同步数据库遇到的坑

可能遇到的各种坑 1.在执行 xp_cmdshell 的过程中出错。调用 ‘CreateProcess’ 失败&#xff0c;错误代码: ‘5’ 网上有各种解决办法&#xff0c;包括改本地安全策略&#xff0c;将sql server服务的网络权限改为本机系统&#xff0c;改cmd用户的读写权限&#xff0c;退出360…

基于WSL2、Ubuntu和VS Code的CUDA平台运行C语言程序

一、CUDA程序执行方法 执行步骤为&#xff1a; 安装Visual Studio Code。在Visual Studio Code中安装插件WSL与电脑的WSL2进行连接。点击左下角&#xff0c;然后再选择连接到WSL。 在WSL中创建以 .cu 为后缀的文件。 rootDESKTOP-HR6VO5J:~# mkdir CUDA /…