与乐高塑料积木 C++ 的组合数量

Posted

技术标签:

【中文标题】与乐高塑料积木 C++ 的组合数量【英文标题】:Number of combinations with LEGO plastic bricks C++ 【发布时间】:2012-05-10 21:11:44 【问题描述】:

您有一些乐高塑料积木,所有积木都是 1x1x1。此外,您还有一块 1xN (N

这是一个例子:

如果图块是 1x7,则有 17 种不同的组合。

输入:7 输出:17

(来源:mendo.mk)

此外,如果您没有积木,则算作 1 个组合。

我已经解决了这个问题,并且我找到了计算图块的最大长度是否为 14(3 个序列)的可能组合的方法。我发现它使用 for 循环。

我最大的问题是我需要运行大量的 for 循环。例如,对于 1 个序列,我使用 1 个 for 循环,对于 2 个序列,2 个循环 + 1 个用于 1 个序列......所以如果我使用所有 80 个砖块,我可以创建 20 个序列,我将不得不使用超过 210 个 for 循环,即数量巨大。因此,如果我可以将它们嵌套在一个中,那就太好了。我试过了,结果很乱,而且没有给出正确的答案。

新代码:

#include <iostream>
using namespace std;
int main()

    long long int places, combinations = 1;
    cin >> places;
    long long int f[80], g[80];
    f[0] = 0;
    f[1] = 0;
    f[2] = 0;
    g[0] = 1;
    g[1] = 1;
    g[2] = 1;
    for(int i = 3; i<=places; i++)
    
        f[i] = f[i-1] + g[i-3];
        g[i] = f[i-1] + g[i-1];
    
    combinations = f[places] + g[places];
    cout << combinations;
    return 0;

【问题讨论】:

你可以通过女巫使用类,你只需要这样做一次,然后一遍又一遍地使用类 我真的不知道它会对我有什么帮助,而且我没有上课的经验,所以请发布一个小例子。如果您没有注意到 1 序列的算法与 2 的算法不同,依此类推 你能解释一下吗? also you must have at least 1 empty space between 2 sequences。您的示例与此陈述不一致 从算法上讲,我不禁注意到砖块的存在与否是bitbinary 状态,而你基本上是shift 模式... :- ) @Mayank 我认为必须连续有 3 个或更多红砖才有效。如果有多个序列,则它必须至少有 1 个砖间隙。 OP 中只有一个 2 个序列的示例(第 3 行的第一个) 【参考方案1】:

如果这是一个计数问题(不输出组合,而只是计数它们),那很容易。假设我们现在求解 n ≥ 3 以求解 n+1,我们通过归纳求解:

假设f 是一个函数,它显示最后一项是砖块的可能方式的数量。 类似地,g 是一个函数,它显示最后一项不是砖块的可能方式的数量。 让h = f+g 定义为所有可能方式的数量。

所以我们有:

f(n+1) = f(n) + g(n-2)
g(n+1) = g(n) + f(n)

有初始条件:

for n=0,1,2: g=1, f= 0.
for n = 3: g=1,f=1

样品:

n=4: g=2,f=2 ==> h=4
n=5: g=4, f= 3 ==> h=7
n=6: g=7, f= 4 ==> h=11
n=7: g=11,f=6 ==> h=17

我们可以在O(n) 中用一个for循环来解决它。


为什么:

f(n+1) = f(n) + g(n-2)
g(n+1) = g(n) + f(n)

首先,证明第一部分:

请记住,我们假设 f(n) 是在最后一项中有塑料砖的有效解决方案,而 g(n) 是在最后一项中没有砖的有效解决方案。

f(n+1) 可以从 f(n) 获得,方法是在最后一个位置添加一块砖。 f(n+1)也可以通过在g(n-2)后面加上三个brick得到,即n-1,n,n+1个单元格。

请注意,我们不能在 g(n-1) 或 g(n) 之后添加砖块来创建 f(n+1) 的有效解决方案,因为它们不是有效解决方案(连续砖块的数量小于 3 )。另外,请注意,我们不需要计算通过在 g(n-3) 之后添加砖块而出现的方式数量,因为它们之前已由 f(n) 枚举。所以我们有f(n+1) = f(n) + g(n-2)

以同样的方式我们可以证明g(n+1) = f(n)+g(n) 这种情况更容易,因为 g(n+1) 可以简单地由直到n 的任何有效解组成,因为这里没有 3 个连续的砖障碍,它们可以在任何有效解决方案之后。

【讨论】:

这个方法很有趣。我尝试了一些值并且它有效,但请告诉我你是如何找到这个的:f(n+1) = f(n) + g(n-2) g(n+1) = g(n) + f(n) @Stefan4024,查看我的更新。我认为这就足够了,如果你想更多地思考自己:) 但如果我的更新有问题,请告诉我编辑它。 我有小问题检查一下,我在第一篇文章中上传了新代码,请告诉我哪里错了。反正。非常感谢赛义德 @Stefan4024,因为你的 f 和 g 是 int 你可以使用 int64 代替。数字很​​大,会溢出。 我怎么会这么笨:S。我对组合做了,却忘了在 f 和 g 上做同样的事情。非常感谢你【参考方案2】:

作为一个受过数学训练而不是 CS 的人,我觉得有必要提一下,虽然 Saeed Amiri 的算法非常好,并且可能足够快地处理 N 到几百万(当然,具有恒定内存),从时间的角度来看,有更好的算法。

我会在他离开的地方接他:

f(n+1) = f(n) + g(n-2)
g(n+1) = f(n) + g(n)

由于 f 和 g 是离散函数,您可以将它们视为序列。于是,这变成了一个递推关系的线性系统。幸运的是,这样的系统可以完全解决,从而可以呈现 f 和 g 的显式形式。 不幸的是,SO 似乎不像 math.SE 那样支持 MathJax,所以我为从这里开始的低质量方程道歉。 让

 | f(n) |
     |f(n-1)|
u(n)=|f(n-2)|
     | g(n) |
     |g(n-1)|
     |g(n-2)|

即u(n)是一个向量行。那么,以下是正确的:

|f(n+1)| |1 0 0 0 0 1| | f(n) | | f(n) | |1 0 0 0 0 0| |f(n-1)| |f(n-1)| = |0 1 0 0 0 0| . |f(n-2)| |g(n+1)| |1 0 0 1 0 0| | g(n) | | g(n) | |0 0 0 1 0 0| |g(n-1)| |g(n-1)| |0 0 0 0 1 0| |g(n-2)|

由此而来的是u(n) = A * u(n-1),其中 A 是上面的矩阵。 然后,u(n) = (A^(n-2)) * u(2),其中u(2) 是向量,包含问题的初始值。这反过来又给出了一个具有O(log(n)) 复杂度的算法,因为您可以使用快速求幂来计算(A^(n-2)),然后将其乘以u(2)

当然,任何这样的技术都可能需要某种 BigInt,否则几乎可以保证溢出。

另请注意,这项技术可以进一步应用: 你可以找到A的特征向量和特征值,然后将u(2)分解成特征向量。然后,您将获得 f(n) 和 g(n) 的封闭形式。

我强烈建议您不要使用基于封闭形式的算法 它几乎肯定会涉及高精度浮点计算(除非所有特征值都是整数,这是极不可能的),从编程的角度来看,这至少具有这种复杂性,并且通常不是恒定时间操作。当然,BigInt 操作也不是。所以恒定时间算法通常是不可行的,而且你可能甚至不需要O(log(n)),因为对于大多数用途来说,线性就足够了。

注意 这里描述的技术可以用于各种问题,并且在动态优化问题中非常有用。另外,通常人们在第一次看到这个时会印象深刻;)

【讨论】:

+1,其实我想用生成器函数来求解递归方程,但通常这超出了这个站点的原则,正如你提到的可能会发生浮点问题,处理 bigInt 也是一样的在我们两个算法中,f,g 呈指数增长,我认为这个算法不适用于 n>100 :) @SaeedAmiri 我同意,我所说的“该算法最多可以运行几百万”的意思是它的运行时间是合理的,并且不会消耗太多的 CPU 秒数。否则,这个序列是指数级的,可能会溢出大约 100(或者甚至更少),所以是的,BigInt 是一个常见的元素 :) 重写方程可以将 g(n) 表示为 2*g(n-1)-g(n-2)+g(n-4)。由此 -> oeis.org/A005252 和封闭形式是:g(n)=(((1+sqrt(5))/2)^(n+1)/sqrt(5)-((1-sqrt(5) ))/2)^(n+1)/sqrt(5)+cos(pin/3)+sin(pin/3)/sqrt(3))/2。可爱的 8)

以上是关于与乐高塑料积木 C++ 的组合数量的主要内容,如果未能解决你的问题,请参考以下文章

C++ 新手需要帮助打印整数组合

模块化墙挂收纳法

设计 | 模块化的微观积木花园LeGrow

梦断代码读后感

C++ 中没有嵌套循环的 2 组合,其中迭代次数等于 2 组合的数量

梦断代码阅读笔记03