C++ 中的笔分配问题2025年5月13日 | 阅读 15 分钟 引言笔分配问题 是一个经典的组合学问题,出现在计算机程序设计竞赛、离散数学和计算机科学中。它是如何将现实生活中的场景进行数学建模的一个绝佳范例。它涉及到在满足某些规则和限制的条件下,将固定数量的相同物品(笔)分配给一群人。 组合学:这是计算分配物品所有可能方式的问题。有许多“组合学”的组合技术,如组合、排列和星星与杠方法。 不可区分的物品:笔是不可区分的(相同的物品),而接收它们的人是可区分的(不同的个体)。这种区别很重要,因为解决问题的方式不同。 约束和变体:改变问题解决方案性质的约束条件有所不同。 无限制分配:如果我们“丢失”任意数量的笔,每个人都可以收到该数量的笔(包括零)。 每人至少一支笔:每支笔都必须分发给至少一个人。 最多,我们每人只能给一支笔。我们每人只能给一支笔(或者如果你成对,可以给两支)。 了解这些约束条件将有助于我们确定哪种方法最适合每种数学变体。 方法一:蛮力法蛮力 方法是解决笔分配问题的最直接方法,无论是第一次学习问题还是处理输入规模较小的情况。这意味着不使用任何特定的数学公式来分配笔给人们,而是系统地创建所有分配笔给人们的方式。在蛮力技术中,对所有情况进行穷举搜索。遵循问题的约束条件,探索、检查和计数每种笔分配的组合。 示例让我们举一个例子,说明在 C++ 中使用蛮力法来解决笔分配问题。 输出 Enter the Number of pens (n): 10 Enter the Number of people (k): 3 --- Unrestricted Distribution --- 0 0 10 0 1 9 0 2 8 0 3 7 0 4 6 0 5 5 0 6 4 0 7 3 0 8 2 0 9 1 0 10 1 0 9 1 1 8 1 2 7 1 3 6 1 4 5 1 5 4 1 6 3 1 7 2 1 8 1 1 9 2 0 8 2 1 7 2 2 6 2 3 5 2 4 4 2 5 3 2 6 2 2 7 1 2 8 3 0 7 3 1 6 3 2 5 3 3 4 3 4 3 3 5 2 3 6 1 3 7 4 0 6 4 1 5 4 2 4 4 3 3 4 4 2 4 5 1 4 6 5 0 5 5 1 4 5 2 3 5 3 2 5 4 1 5 5 6 0 4 6 1 3 6 2 2 6 3 1 6 4 7 0 3 7 1 2 7 2 1 7 3 8 0 2 8 1 1 8 2 9 0 1 9 1 10 Total ways (Unrestricted): 66 --- At Least One Pen per Person --- 1 1 8 1 2 7 1 3 6 1 4 5 1 5 4 1 6 3 1 7 2 1 8 1 2 1 7 2 2 6 2 3 5 2 4 4 2 5 3 2 6 2 2 7 1 3 1 6 3 2 5 3 3 4 3 4 3 3 5 2 3 6 1 4 1 5 4 2 4 4 3 3 4 4 2 4 5 1 5 1 4 5 2 3 5 3 2 5 4 1 6 1 3 6 2 2 6 3 1 7 1 2 7 2 1 8 1 1 Total ways (At Least One Pen): 36 --- At Most One Pen per Person --- Too many pens for each person to get at most one. --- Equal Distribution --- Cannot equally distribute pens among people. --- Distribution with Maximum Limit per Person --- Enter the maximum Number of pens a person can receive: 1 Total ways (Max Limit 1 pens per person): 0 说明该代码为根据不同的分配规则,将 n 支笔分配给 (k) 个人提供了蛮力解决方案。每个辅助函数都使用递归和回溯来解决问题的不同变体。
复杂度分析时间复杂度 无限制分配 (countWaysUnrestricted)
每人至少一支笔 (countWaysAtLeastOne)
每人最多一支笔 (countWaysAtMostOne)
带最大限制 (countWaysWithMaxLimit)
空间复杂度 所有函数的空间复杂度
方法二:动态规划动态规划 (DP) 可以为我们提供更有效的解决方案。DP 方法通过重叠子问题来解决问题,将问题分解成小的子问题,并存储这些子问题的结果以避免重复计算。例如,我们在无限制分配中使用“星星与杠”方法,目标是将 n 个相同的物品分成 k 个箱子。DP 有助于优化此过程,从而显著降低时间复杂度。通过使用此方法,我们可以在合理的时间内解决具有更大输入规模的问题。 示例让我们举一个例子,说明在 C++ 中使用动态规划来解决笔分配问题。 输出 Enter the Number of pens (n): 10 Enter the Number of people (k): 3 --- Unrestricted Distribution (DP) --- Total ways (Unrestricted): 66 --- At Least One Pen per Person (DP) --- Total ways (At Least One Pen): 36 --- At Most One Pen per Person (Combination) --- Total ways (At Most One Pen): 0 --- Equal Distribution (DP) --- Total ways (Equal Distribution): 0 Enter the maximum Number of pens a person can receive: 1 --- Distribution with Maximum Limit per Person (DP) --- Total ways (Max Limit): 0 说明countWaysUnrestrictedDP
countWaysAtLeastOneDP
countWaysAtMostOne
countWaysEqualDistribution
countWaysWithMaxLimit
复杂度分析时间复杂度 无限制分配 (countWaysUnrestrictedDP) 这是因为我们要填充一个大小为 (k+1)×(n+1) 的 DP 表,该表根据前一个表中的值进行计算。我们计算每个人(在 1 到 k 之间)使用简单的递推关系分配最多 n 支笔的方式数量。因此,时间复杂度为 O(k⋅n)。 每人至少一支笔 (countWaysAtLeastOneDP) 我们首先给每个人分配 1 支笔,剩下 n-k 支笔。然后,问题被简化为对所有剩余的笔进行无限制分配,并使用 countWaysUnrestrictedDP 函数来计算。此步骤的最坏情况时间复杂度为 O(k⋅(n - k)),因为我们对这些剩余的笔进行了 DP 计算。 每人最多一支笔 (countWaysWithMaxLimit) 为了填充 DP 表,我们考虑到所有人都可能获得 0 到 maxPens 支笔。这导致了三个嵌套循环:两个用于人数,两个用于笔,以及一个内部循环用于可以分配笔的最大人数。因此,时间复杂度为 O(k ⋅n⋅maxPens)。 空间复杂度 无限制分配 (countWaysUnrestrictedDP) DP 表是一个 (k+1)×(n+1) 的二维 数组,其中每个条目存储了将 j 支笔分配给 i 个人可能的方式数量。它直接导致空间复杂度为 O(k⋅n)。k 是人数,n 是笔的数量。 每人至少一支笔 (countWaysAtLeastOneDP) 因此,空间复杂度为 O(k⋅n)。该函数利用 countWaysUnrestrictedDP 函数,该函数使用 DP 表来计算在给每个人一支笔后,分配剩余 n-k 支笔的方式数量。 每人最多一支笔 (countWaysAtMostOne) 该函数以迭代方式计算二项式系数 C(k,n),在函数中使用了常量的变量。因此,空间复杂度为 O(1)。 每人最多一支笔 (countWaysWithMaxLimit) 在此函数中,DP 表与无限制分布情况下的类似,维度为 (k+1)×(n+1),因此空间复杂度为 O(k⋅n),其中 k 是人数,n 是笔的数量。 下一个主题C++ 中的访问者设计模式 |
A 是一个程序,旨在根据预定义的单词列表自动填充给定的填字游戏网格。问题陈述:一个填字游戏由以下几部分组成:一个单元格网格(通常是方形或矩形),其中一些单元格可能被涂黑。一个包含要...的单词列表。
阅读 10 分钟
在本文中,我们将讨论 C++ 中的 Chalkboard XIR 游戏。问题陈述:此问题涉及一个游戏,玩家使用一个名为 countnums 的整数数组在黑板上写数字。Radha 和 Bob 是两个玩家,他们轮流从...
阅读 4 分钟
在本文中,我们将讨论如何在 C++ 中从派生类调用虚函数及其优势。简介:多态性是面向对象编程(尤其是在 C++ 中)的主要特性之一。换句话说,它指的是多种形式的出现。这些不同的...
7 分钟阅读
在本文中,我们将讨论 C++ 中的 std::is_destructable,包括其语法和示例。什么是 std::is_destructable?在 C++ 中,std::is_destructable 是一种类型特征函数。它有助于确定某种类型是否可以使用 delete 运算符进行销毁。它定义在 <type_traits>...
阅读 3 分钟
Jolly Jumper Sequence 是数学中的一个概念,非常有趣。它完全是关于系列中连续数字之间的绝对差值。如果给定的系列包含从 1 到 n-1 的所有数字...
阅读 8 分钟
在数字王国中,特殊的性质和独特的模式在数学领域广阔无垠,有些想法因其稀缺性而显得特别。令人兴奋的是,发现所谓的 Magnanimous Numbers 是其中引人入胜的想法之一。Magnanimous Number……
阅读 10 分钟
对角线占优是指一个矩阵,如果主对角线以外所有元素的总和小于主对角线上的元素总和。在这种情况下,方阵的整数,如果主对角线上的任何元素的值...
5 分钟阅读
概述 一种特殊的矩阵,它为从一边翻滚到另一边的每个正交元素保持一致性,这种矩阵被称为托普利兹矩阵。它以德国数学家奥托·托普利兹 (Otto Toeplitz) 的名字命名。这些矩阵表示法可以在多个不同的……
阅读 8 分钟
命令设计模式是一种行为模式,它通过将请求编码为一个对象来解耦请求者和接收者,从而能够使用不同的请求、请求顺序定制客户端,并支持可用于...
阅读 4 分钟
在数论和组合学的领域中,弗罗贝尼乌斯数是源自一个经典数学问题(在娱乐数学中称为硬币问题或鸡块问题)的著名概念。这个问题围绕着确定最大整数的想法……
阅读 8 分钟
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India