【问题标题】:need woodcutting recursion advice需要木刻递归建议
【发布时间】:2015-04-12 05:24:12
【问题描述】:

给你一个长度为“n”的木头。日志上有“m”标记。必须在每个标记处切割原木。切割成本等于被切割原木的长度。给定这样的原木,确定切割成本最低。

我的部分解决方案是使用递归: 当我按顺序进入标记阵列时,即从第 0 次切割到阵列切割结束时,我能够获得成本。然而,当我们不按顺序切割时,我被困在如何为序列编写代码,即在随机序列中,例如代码可以解释切割不按顺序的情况,并为所有这些情况取最大值。

一种解决方案是对标记数组进行所有排列。为所有排列调用木刻函数并取最大值,但这似乎是幼稚的方法。

有什么建议吗?

标记 = [2, 4](切割点)

int woodcut(length, cut_point, index){
    if (cut_point > length)
            return INFINITY
    first_half = cut_point;
    second_half = length - cut_point
    if (markings[index++] == exist) {
            if (next_cut_point > first)
                    cost = length + woodcut(second_half, next_cut_point-first)
            else    
                    cost = length + woodcut(first_half, next_cut_point)  
    } else if (index >= sizeof(markings))
            return cost;
}

http://www.careercup.com/question?id=5188262471663616

在查找答案并在一些慷慨的人的帮助下,我能够编写以下解决方案:

    #include <stdio.h>

    int min(int a, int b)
    {
            return a>b?b:a;
    }

    int min_cut(int first, int last, int size, int *cuts)
    {
            int i;
            unsigned int min_cost = 1U<<30;
            /* there are no cuts */
            if (size == 2)
                    return 0;
            /* there is only one cut between the end points */
            if (size == 3)
                    return last - first;
            /* cut at all the positions and take minimum of all */
            for (i=1;i<size;i++) {
                    if (cuts[i] > first && cuts[i] < last) {
                            int cost = last-first + min_cut(first, cuts[i], i+1, cuts) +
                                                    min_cut(cuts[i], last, size - i, cuts);
                            min_cost = min(cost, min_cost);
                    }
            }
            return min_cost;
    }

    int main()
    {
            int cuts[] = {0, 2, 4, 7, 10};
            int size = sizeof(cuts)/sizeof(cuts[0]);
            printf("%d", min_cut(cuts[0], cuts[size-1], size, cuts));
            return 0;
    }

【问题讨论】:

  • 您的问题可以使用格式。 stackoverflow.com/editing-help
  • 您应该说明问题的根源,并在可能的情况下提供链接。
  • @DouglasZare:没有来源。我是从参加谷歌面试的人问到的职业杯网站上得到的。
  • 这是一个来源。您应该在问题陈述中包含这一点,并链接到讨论该问题的职业杯网站。
  • 再次,您可以编辑问题以包含该问题。这至少有两个好处。首先,它可以让有兴趣的人看到其他人在该线程上提出的解决方案,以避免重复工作。其次,适当的归因意味着您不会试图声称发明问题的功劳。

标签: algorithm recursion dynamic-programming


【解决方案1】:

方法 A:

首先编写一个朴素的递归函数,计算从ith 标记到jth 标记的最便宜的切割成本。通过在所有可能的第一次切割中取第一次切割的成本加上切割两个侧面的最低成本来做到这一点。

记住这个函数,让它更高效。

方法 B: 计算一个值表,用于计算从ith 标记到jth 标记的最便宜的切割成本。使用标记数量ij 分开的外循环,然后使用i 的内循环,然后是可能进行第一次切割的非常内循环。

这两种方法都有效。两者都是O(m*m*m) 我通常会采用方法 A。

【讨论】:

  • 介意为“A”方法提供一些代码 sn-p 吗?或者为“第一次切割的成本加上切割两个侧面的最低成本”在所有可能的第一次切割中提供更多解释
  • 类似这样:如果木材的长度是 '10' 并且切割点是 [4, 6] 如果切割点是 '6' 那么 min_cost[0, 10] = 10 + min (min_cost[0, 6], min_cost[6, 10]) min_cost[0, 6] = 6 + min(min_cost[0, 6], min_cost[6, 10])
  • @newbie_old 当我看到这样的事情时,我的假设是这个人正在寻求编程竞赛或家庭作业的帮助。因此,我限制了我将提供多少帮助。
  • 如果你看过我对这个问题的最新编辑,你不会得出这个结论,无论如何我现在正在编写代码,一旦完成就会发布。
【解决方案2】:

动态编程。复杂度 O(m^3)。 python中的解决方案。输入为标记位置的有序列表,最后一项为日志长度:

def log_cut(m):
  def _log_cut(a, b):
    if mat[a][b]==None:
      s=0
      min_v=None
      for i in range(a+1, b):
         v=_log_cut(a, i)+_log_cut(i, b)
         if min_v==None or v<min_v:
           min_v=v
      if min_v!=None:
        s=min_v+m[b-1]
        if a>0:
          s-=m[a-1]
      mat[a][b]=s
    return mat[a][b]

  mat=[[None for i in range(len(m)+1)] for j in range(len(m)+1)]
  s=_log_cut(0, len(m))
  return s

【讨论】:

    【解决方案3】:

    这种情况类似于分而治之的排序。以快速排序为例:

    • 有一个分区步骤需要对阵列进行线性传递以将其分成两个子阵列。同样,切割原木的成本等于其长度。
    • 然后有一个递归步骤,其中每个子数组都被递归排序。同样,您必须递归地继续切割原木被切割成的两块中的每一个,直到切割完所有标记。

    当然,快速排序在最佳情况下是 O(n log n),当每个分区步骤(基本情况除外)将数组分成两个大小几乎相等的子数组时,就会发生这种情况。因此,您需要做的就是找到最靠近中间的标记,“切割”那里的日志,然后递归。

    【讨论】:

    • 这种启发式方法在许多示例中都不会产生最佳切割。假设在长度为 200 的原木中,标记分别为 1、99、100、101 和 199。您可以将原木切成两半,之后您别无选择,总成本为 200 + 100 + 100 + 99 + 99 = 598。如果改为削减 99、101、1、199、100,则总成本为 200 + 101 + 99 + 99 + 2 = 501。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    相关资源
    最近更新 更多