【问题标题】:Project Euler #219欧拉计划 #219
【发布时间】:2008-12-06 20:13:00
【问题描述】:

我正在尝试进行 Euler 编号 219 项目,但未能掌握它。我正在尝试使用 Python,根据 Euler 项目,它应该能够在一分钟内完成!这让我认为他们不可能希望我计算每个单独的位串,因为这在 Python 中太慢了 - 必须有一个 sub O(n) 算法。

我查看了一个递归解决方案,它存储位串可能的前缀,以便它可以快速选择一个新位串,甚至将它们分组考虑。这仅适用于超过 10 的暴力破解值:

cost(1) = 1
cost(2) = 5
cost(3) = 11
cost(4) = 18
cost(5) = 26
cost(6) = 35
cost(7) = 44
cost(8) = 54
cost(9) = 64
cost(10)= 74
cost(11)= 85
cost(12)= 96

过去,我正在努力理解如何减少问题。总是有可能做出这样的模式:

1
01
001
0001
00001
00000

但对于超过 7 个位串来说,它并不是最优的。谁能指导我应该考虑什么?

【问题讨论】:

  • 我投票决定将此问题作为题外话结束,因为 Project Euler 明确要求人们不要在网上发布他们问题的答案。 StackOverflow 通过发布他们所有问题的答案来破坏他们的网站是一种糟糕的形式。

标签: algorithm math bitstring


【解决方案1】:

蛮力不是正确的方法。这是其中一个问题,如果你知道某件事,这并不难,但如果你从未听说过那件事,那几乎是不可能的。那东西是Huffman trees

[编辑] 经过进一步审查,您似乎无法在具有特定频率的 N 个节点上完全构建 Huffman 树,因为字符串的成本函数是 4*(# of 1's) + (# of 0's) .如果成本函数是字符串的长度(或其倍数),那么您可以创建一棵 Huffman 树。

任何无前缀代码集都可以表示为类似 Huffman 的二叉树,其中每个节点有 0 或 2 个子节点,叶子节点表示代码。给定一棵有 N 个节点的树,我们可以构造一棵有 N+1 个节点的树,如下所示:

  1. 选择成本最小的叶节点,其中叶节点的成本为 4*(从根到叶的路径上的 1 数)+(路径上的 0 数)
    • 向该节点添加 2 个子节点

因此,如果节点的代码以前是 xxxx,那么我们从代码集中删除该代码(因为它不再是叶子),并添加两个代码 xxxx0 和 xxxx1。代码集的总成本现在增加了

`成本(xxxx0) + 成本(xxxx1) - 成本(xxxx) = 成本(0) + 成本(1) + 成本(xxxx) = 5 + 成本(xxxx)

因此,mincost(N+1)

如果是等式,那么要解决这个问题,你会这样做:

  1. 从总成本为零的空代码集开始
    • 从 1 迭代到 109,执行:
      1. 在您的代码集中查找最便宜的代码
    • 通过附加 0 和 1 将该代码分成两部分
    • 将该代码的成本 + 5 加到总成本中

如果您使用priority queue,您应该能够在 O(N log N) 时间内完成此操作。考虑到 109 的上限,这可能可行,也可能不可行。

【讨论】:

    【解决方案2】:

    Adam:感谢您提供的链接 - 它看起来非常很有希望!在阅读 Wikipedia 文章后我不确定的是如何考虑 4 的系数。我正在努力将 Project Euler 问题“映射”到算法。字母表的长度必须是 10^9 项,但重量是多少?

    另一件困扰我的事情是霍夫曼编码充其量是 O(n) 肯定太慢了,正如我上面提到的......

    mattiast:我不认为你的复发有效(或者我误解了它!)。我的解释是:

    def cost(n):
        if n == 1: return 1
    
        m = None
        for k in range(1, n):
            v = cost(k)+cost(n-k)+k+4*(n-k)
            if not m or v < m: m = v
    
        return m
    
    print(cost(6))
    

    它返回的值是41,而应该是35。同样,如果我的值是正确的,那么我在ATT的整数序列百科全书中找不到差异。

    【讨论】:

    • 您的基本情况是错误的 - 对于 n=1,使用“空”位串的总成本为 0。
    • 没错,我告诉过你要发挥你的想象力!只要看看差异,你就会注意到序列的某种形状。我不想破坏你所有的乐趣:)
    【解决方案3】:

    N = 10**9

    t = [0]

    对于 xrange(N) 中的 c : 米 = 分钟(吨) t.remove(m) t.append(m+1) t.append(m+4) 打印总和(t),t

    【讨论】:

      【解决方案4】:

      我是如何解决的,计算 Cost(n) 直到 n=1000,然后只是猜测它是如何从那里开始的。如果你看连续值的差异,并使用The encyclopedia of integer sequences(和一些想象),你可以猜出规则。

      您可以使用递归Cost(n) = min {Cost(k)+Cost(n-k)+k+4*(n-k) | 0 &lt; k &lt; n},通过一种动态规划计算小(

      【讨论】:

        【解决方案5】:

        Adam Rosenfield 的解决方案看起来很有可能奏效。这里已经很晚了(大约午夜!)所以我会一直留到早上。我在 C 中高效地实现了优先级队列,所以明天我将尝试使用它并找到解决方案。

        我将报告算法是否成功,但推理对我来说似乎是合理的,并且与数据非常吻合(如上所述)。但是,正如我一直在喃喃自语,一定有一个 sub O(n) 算法! ;-)

        【讨论】:

          【解决方案6】:

          事实证明,O[n*log(n)] 并不算太慢,但内存复杂度大约为 O(n)。然而,上面提出的算法可以进一步降低到 O(n) 时间复杂度和低内存复杂度。为此,可以使用数组 x,其中 x[a] = 成本 a 的数值数。

          所做的假设给出了 10^9 的正确结果,所以我认为它们是正确的。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多