【问题标题】:knapsack-like algorithm背包式算法
【发布时间】:2012-04-28 17:05:40
【问题描述】:

这是我发现的一个非常有趣的 java 问题:

在发现书籍印刷之前,书籍是由某些称为“作家”的人复制的。 簿记员有一叠 N 本书需要复制。为此,他有 K 个作家。每本书可以有不同的页数,每个作者只能从堆栈顶部取书(如果他取书 1,那么他可以取书 2,但不能取书 4 或书 5)。簿记员知道每本书的页数,他需要在作者之间共享书籍,以使作者必须复制的最大页数尽可能少。例如,当然不能拆分页面你不能把一本 30 页的书分成 15 页和 15 页。

例如,如果我们有 7 本书,有 3 位作者,并且相应的书籍页数为:30 50 5 60 90 5 80,那么最佳解决方案是第一位作者拿前 4 本书,第二位作者拿下一本书,然后最后两本书的第三个,所以我们会有:

第 1 = 145 页
第 2 = 90 页
第 3 = 85 页

所以程序是编写一个算法来找到在作者之间共享页面的最佳解决方案。因此,在程序结束时,您必须显示每个页面有多少页。

这是几年前的一次编程比赛,我想试一试,到目前为止我发现如果你把所有书籍的总页数除以你的作者数量在示例中获取 106.66 页,然后您尝试将堆栈中最接近该数字的连续书籍提供给每个作者,但这对于大页码根本不起作用,特别是如果一本书的页数有超过总页数除以作者人数

因此,如果您愿意,请分享您的意见并提供提示和提示,数学或其他,这是一个非常有趣的算法!

【问题讨论】:

  • “所以程序是编写一个算法,找到在作者之间共享页面的最佳解决方案。”
  • 换句话说,哪些书给了哪个作家,但页面是最重要的,所以每个人最终会有多少页
  • @SiliconTouch:所以你是在找人为你写算法?
  • 根据常见问题解答,“分享您的意见”-问题不好,因为很难找到“正确答案”。
  • 顺便说一句:据我了解,您的示例是错误的(在撰写本文时,它指出:30 50 5 60 90 5 80->85/150/85 当正确答案是 145/90/85 时)问题。

标签: java algorithm stack division


【解决方案1】:

我想出了一个直截了当的解决方案,可能效率不高,但逻辑有效。基本上,您从作家的数量开始与书籍的数量相同,然后减少,直到您拥有作家的数量。

举个例子。假设你从你的七个值开始,30 50 5 60 90 5 80。对于每一步,你通过总结“最低对”来减少一个。粗体的值是要进行下一次迭代的对。

7
30 50 5 60 90 5 80
6
30 55 60 90 5 80
5
30 55 60 90 85
4
85 60 90 85
3
145 90 85

通过一些伪编程,这个例子展示了它是如何实现的

main(books: { 30 50 5 60 90 5 80 }, K: 3)

define main(books, K)
  writers = books
  while writers.length > K do
    reduceMinimalPair(writers)
  endwhile
end

define reduceMinimalPair(items)
  index = 0
  minvalue = items[0] + items[1]
  for i in 1..items.length-1 do
    if items[i] + items[i + 1] < minvalue then
      index = i
      minvalue = items[i] + items[i + 1]
    endif
  endfor
  items.removeat(index)
  items.removeat(index + 1)
  items.insertat(index, minvalue)
end

【讨论】:

  • 这实际上看起来可以工作,在 java 中,虽然我必须用一个列表而不是我想的数组来实现它(因为你也必须删除项目)。我说的对吗?
  • @SilliconTouch:是的,您可以用一个替换两个项目。数组可以工作,但你最终会做更多的工作,因为你必须将值从较高的索引转移到较低的索引。在此示例中,列表应该最有效。
  • 当问题在 java 标签下时,尝试仅使用 java 代码回答
【解决方案2】:

假设您有书 1...n,页面为 b1,b2,...,bn。假设您有 K 个作家。

初始化一个矩阵 F[1...n,1...K]=infinity。

令 F[i,1]= sum_j=1..i (bj)

现在,对于每 k=2..K

F[i,k] = min_j=1..i( max(F[j,k-1], sum_r=j+1..i (br) )

【讨论】:

  • 我读过关于背包问题的文章,但你所说的对我来说似乎很混乱,因为我不了解动态规划。我是一名大学生,还没有学过动态编程,所以如果你能再解释一下,我会很高兴
  • @SilliconTouch 对不起。我没有意识到您只能将连续的书块分配给每个作家。我已经相应地更新了解决方案。
  • 是的,我也看到了您更新的解决方案,这是我无法真正理解的部分......
  • 这对我的小脑袋来说太混乱了,但我真的很感谢你的帮助
  • @SilliconTouch 现在我几乎要给出确切的程序了!
【解决方案3】:

我认为您认为的方式是正确的,但是如果您说它不适用于大数字,那么也许您应该检查是否存在比平均值更大的数字,并在这种情况下执行其他操作。也许删除数字并从一开始就将其提供给作家或类似的东西

【讨论】:

    【解决方案4】:

    除了使用动态编程解决它,您还可以二进制搜索每个人都不会复制超过此页数的页数上限。当这个数字收敛时,这就是答案。

    【讨论】:

    • 所以你的意思是找到最多的人可以复制的页面,而不是让任何人超过这个限制?如果是这样,如何找到该号码?您说二进制搜索,但我只知道如何使用二进制搜索在数组中查找数字。如何使用二分搜索来查找作者复制的最多页面?
    • 你猜一个数字并测试是否有可能没有人复制超过这个页数并完成书籍。有一个数字 X,所有小于 X 的数字都是不可能的,所有大于或等于 X 的数字都是可能的。你对 X 进行二分搜索。
    猜你喜欢
    • 2016-12-23
    • 1970-01-01
    • 1970-01-01
    • 2015-06-22
    • 2011-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多