您将获得一根长度为X的木棍,在任意位置(整体)上有m个标记,并且标记表示相应地进行切割的位置。用于切割L长度的棒 分成两块,木匠收费L美元(无论这两块是否长度相等都没关系,即斩波成本与斩点的位置无关)。 设计一个动态编程算法,计算最低总成本。
无法弄清复发。 在最近的一次编程采访中被问到这一点。
答案 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:
好吧,O(m ^ 3)并不是每个人的梦想,但这是我能够迅速提出的最好的结果(在Per的帖子中获得一些灵感后,我发现之前的效率低下)。
答案 1 :(得分:1)
为每对(标记|终点)s计算切割杆段的最便宜的方法。对于每个细分,最小化该细分中第一个剪辑的选择。
答案 2 :(得分:0)
我猜你想要木匠一次切割,然后继续切割,直到棍子全部切开,你是否要求切割的顺序?
在这种情况下,一种方法是通过可能组合树进行深度优先递归搜索,在此计算成本,记录第一个序列及其成本,并从那时开始,避免下降到成本较高的树木,并始终记录您找到的任何更便宜的序列。