C++ 中的格朗迪数2025年5月12日 | 阅读 7 分钟 Grundy 数,也称为 Nim 数,对于解决 C++ 中的组合博弈论问题至关重要。它们代表游戏中位置的最小排除 (mex) 值,决定着胜负状态。通过计算 Grundy 数,玩家可以预测最优走法并分析游戏结果。 示例输入:从 5 个物品开始。 输出 5 的 Grundy 数为:1 从 5 个物品开始是一个获胜局面。 说明对于一个有 5 个物品的堆,其 Grundy 数为 1,表示这是一个获胜局面。这意味着玩家可以走一步,使对手处于一个失败局面(Grundy 数为 0)。通过策略性地移除 1、2 或 3 个物品,当前玩家可以控制游戏的结果。 方法 1:带记忆化的动态规划。算法步骤 1:定义目标:我们的目标是确定起始堆大小 n 是获胜局面还是失败局面。我们将计算从 0 到 n 的每个堆大小的 Grundy 数,其中 Grundy 数为 0 表示失败局面(无获胜走法),而任何其他数字表示获胜局面。 步骤 2:基本情况:对于一个有 0 个物品的堆,Grundy 数为 0,因为没有可用的走法了。轮到该玩家,他输了,因此这是一个失败局面。 步骤 3:每个位置的递归计算:对于任何堆大小 n:检查可能的走法:移除 1、2 或 3 个物品。对于每种走法,计算由此产生的堆大小的 Grundy 数(例如,如果我们移除 1 个物品,我们需要 n-1n-1 的 Grundy 数)。将这些产生的 Grundy 数存储在一个集合中。此步骤捕获了当前堆大小的所有可能结果。 步骤 4:计算最小排除值 (mex):下一步是找到不在产生的 Grundy 数集合中的最小非负整数(这称为“最小排除值”或 mex)。选择 mex 值是因为它代表了当前位置无法达到的最小 Grundy 数,使其成为对手的最佳走法。 步骤 5:效率记忆化:为避免为每个堆大小重新计算 Grundy 数,请将计算出的值存储在记忆化表中(一个 数组)。如果特定堆大小的 Grundy 数已计算,我们将直接使用它,而不是重新计算。 步骤 6:最终决策:根据计算出的起始堆大小 n 的 Grundy 数:如果为 0,则这是一个失败局面(因为没有走法可以将对手置于失败局面)。如果为任何正数,则这是一个获胜局面(当前玩家有办法让对手处于失败局面)。 程序输出 Grundy Number for 5 is: 1 Starting with 5 items is a winning position. 复杂度分析时间复杂度 由于记忆化,该算法的时间复杂度为 O(n)。每个从 0 到 n 的 Grundy 数只计算一次,因为会重用之前的结果。检查可能的走法(移除 1、2 或 3 个物品)是常数时间 O(1),这使得该方法对于较大的 n 值都很高效。 空间复杂度 空间复杂度为 O(n),因为我们将从 0 到 n 的每个堆大小的 Grundy 数存储在一个数组中。此记忆化表可避免重复计算。额外的空间使用非常少,因为只需要一个常数集合来跟踪每个位置可能的 Grundy 值。 方法 2:自底向上动态规划自底向上动态规划方法是一种有效且高效的方法,可以在无需递归调用的情况下计算各种堆大小的 Grundy 数。该方法不是从目标堆大小开始并通过递归计算将其分解,而是从最小可能的堆(0 个物品)开始,然后依次构建。 程序输出 Grundy Number for 5 is: 1 Starting with 5 items is a winning position. 说明初始化和 Grundy 数组设置
Grundy 数的迭代计算
探索可能的走法 对于每个堆大小 i,玩家可以移除 1、2 或 3 个物品,只要 i 足够大即可进行该走法。
计算最小排除值 (mex)
最终决策和输出
复杂度分析时间复杂度 此自底向上动态规划方法的时间复杂度为 O(n)。 对 n 个值进行单次迭代
每个堆大小的固定操作
总而言之,由于我们对每个堆大小(最多为 n)执行恒定的工作量,因此总时间复杂度为 O(n)。 空间复杂度 空间复杂度为 O(n)。 Grundy 数组
临时集合 nextGrundy
因此,总空间复杂度主要由 grundy 数组决定,结果是 O(n) 空间复杂度。 下一个主题C++ 中的 Skip List |
在本文中,我们将讨论在 C++ 中遇到数字时如何反转字符串。问题陈述问题是在字符串中每当遇到数字时反转字符串的片段。换句话说,由数字之间的字符组成的每个片段都应该...
阅读 4 分钟
Pandigital 数字是数学家感兴趣的主题,因为它们的构造一方面限制了它们,另一方面又具有简单的结构。利用给定数字在特定范围内恰好使用一次的数字被称为...
11 分钟阅读
外星词典问题不仅有趣,而且令人兴奋;在这个问题中,我们需要根据给定外星语言的单词列表来找出该外星语言中某个字符的顺序。这些单词按字典顺序给出……
阅读 13 分钟
在现代 C++(从 C++20 开始)中,通过三向比较的概念(通常称为宇宙飞船运算符 (<=>))引入了一种强大而直观的比较对象和值的方法。此运算符允许您比较两个对象并获得一个单一值...(省略)
阅读 8 分钟
C++ 简介 C++ 由 Bjarne Stroustrup 于 20 世纪 80 年代初在贝尔实验室开发。它是一种基于 C 编程语言的通用且强大的编程语言。其主要目标是在保持效率和灵活性的同时引入面向对象编程特性...
阅读 4 分钟
一个数字可以写成两个或多个连续正整数之和的不同方式,是数学中一个有趣的“数字礼貌度”概念。以下文章探讨了数学中礼貌度的定义,并展示了如何...
阅读 4 分钟
在本文中,我们将通过几种方法和示例讨论 C++ 中的堆栈展开。什么是?当 C++ 中抛出异常时,会发生称为堆栈展开的过程。异常发生后,C++ 运行时系统会开始展开或……
阅读 4 分钟
引言 快速行进法 (FMM) 是一种计算方法,在应用于 Eikonal 方程时显示出巨大的优势,该方程用于涉及波传播、计算机视觉、水力学甚至医学成像的各种应用。Sethian J.A. 引入的一些新颖方法...
阅读 16 分钟
在本文中,我们将讨论其算法、伪代码和示例。什么是?如果一个整数 N 的前缀满足某些整除要求,那么这个数就被称为多重整除数。一个有 k 位数字的整数 N 的第一位数字必须是...
阅读 4 分钟
Std::move_only 是一种在 C++ 中引入的对象类型,它只能移动(不允许复制)。这种类型与 std::functionality 类似。Web 将能够通过链接计算各种实体提供的内容之间的含义。但是,移动构造函数是...
阅读 4 分钟
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India