棒切割的变种

时间:2011-11-13 21:29:37

标签: algorithm dynamic-programming

您将获得一根长度为X的木棍,在任意位置(整体)上有m个标记,并且标记表示相应地进行切割的位置。用于切割L长度的棒 分成两块,木匠收费L美元(无论这两块是否长度相等都没关系,即斩波成本与斩点的位置无关)。 设计一个动态编程算法,计算最低总成本。

无法弄清复发。 在最近的一次编程采访中被问到这一点。

3 个答案:

答案 0 :(得分:4)

使用m个标记,您有m + 2个有趣点,0 =左端点,标记1,...,m,右端点=(m + 1)。
将有趣点0的距离存储到数组中的有趣点i以计算成本 编辑:(Doh,无偿地介绍了一个不必要的循环,再次看到Per的答案后注意到)
对于每个0 <= l < r <= m+1,让cost[l][r]成为完全切断点l和r之间的片段的最低成本。解决方案是cost[0][m+1]

// Setup
int pos[m+2];
pos[0] = 0; pos[m+1] = X;
for(i = 1; i <= m; ++i){
    pos[i] = position of i-th mark;
}
int cost[m+2][m+2] = {0};
for(l = 0; l < m; ++l){
    // for pieces with only one mark, there's no choice, cost is length
    cost[l][l+2] = pos[l+2]-pos[l];
}
// Now the dp
for(d = 3; d <= m+1; ++d){  // for increasing numbers of marks between left and right
    for(l = 0; l <= m+1-d; ++l){ // for all pieces needing d-1 cuts
        // what would it cost if we first chop at the left most mark?
        best_found = cost[l+1][l+d];
        for(i = l+2; i < l+d; ++i){ // for all choices of first cut, ssee if it's cheaper
            if (cost[l][i] + cost[i][l+d] < best_found){
                best_found = cost[l][i] + cost[i][l+d];
            }
        }
        // add cost of first chop
        cost[l][i][l+d] = (pos[l+d] - pos[l]) + best_found;
    }
}
return cost[0][m+1];

复杂性:如果你天真地检查所有可能的切割方法,那就是m!方法。很坏。 考虑到在任何切割之后无论你是先完全切断左边部分,然后是右边还是交错切割这两部分,复杂度(对于m> = 2)减少到{{1} }。还是很糟糕。
对于我们的dp:

  1. 最里面的循环,循环i; d-1(1&lt; i&lt; 1 + d)
  2. 在l:m + 2-d(0 <= 1 <= m + 1-d)上循环,得到(m + 2-d)*(d-1)
  3. 最外圈,3 <= d <= m + 1,大致为m ^ 3/6步。
  4. 好吧,O(m ^ 3)并不是每个人的梦想,但这是我能够迅速提出的最好的结果(在Per的帖子中获得一些灵感后,我发现之前的效率低下)。

答案 1 :(得分:1)

为每对(标记|终点)s计算切割杆段的最便宜的方法。对于每个细分,最小化该细分中第一个剪辑的选择。

答案 2 :(得分:0)

我猜你想要木匠一次切割,然后继续切割,直到棍子全部切开,你是否要求切割的顺序?

在这种情况下,一种方法是通过可能组合树进行深度优先递归搜索,在此计算成本,记录第一个序列及其成本,并从那时开始,避免下降到成本较高的树木,并始终记录您找到的任何更便宜的序列。