你必须把一根长棍切成l
几块.必须在位置c1, c2, c3, ..., cn
处进行切割,其中ci
是整数1
和n-1
(包括)之间的整数.切割的成本等于制作它的棒的长度.削减的顺序应该是什么,以最大限度地降低运营的总成本?
例如,考虑长度10
和切割必须在位置进行切割2, 4, 7
.你可以按照给定的顺序切割木棒.第一次切割会花费10
,因为棒是长度的10
.第二次切割会花费8
,因为切割所用的剩余棒是长度的10 - 2 = 8
.最后的削减将花费6
,因为剩余的棍子的长度是10 - 4 = 6
.总费用是10 + 8 + 6 = 24
但是,如果我们按顺序切割棒:4, 2, 7
我们得到的成本10 + 4 + 6 = 20
对我们来说更好.
设计一种算法来解决问题.
我很确定这是一个DP问题.我能看到的一个诱人的复发关系是,如果我们切一根棍子,我们会得到两根小棍子.如果我们知道这两种棒的最佳解决方案,我们可以很容易地找出更大棒的最佳解决方案.但这样效率很低.
如果你有一个递归函数min_cost(stick_length, c_1, c_2, ..., c_n)
,它返回切割长度stick_length
为的最小成本c_1, c_2, ..., c_n
,则递归关系看起来像这样
min_cost(stick_length, c_1, c_2, ..., c_n) =
stick_length
+ minimum(min_cost(c_1, a_1, a_2, ..., a_i)
+ min_cost (stick_length - c_1,
a_(i+1), ..., a_(n-1)),
min_cost(c_2, a_1, a_2, ..., a_i)
+ min_cost(stick_length - c_2,
a_(i+1), ..., a_(n-1)), ... ,
min_cost(c_n, a_1, a_2, ..., a_i)
+ min_cost(stick_length - c_n,
a_(i+1), ..., a_(n-1)))`,
Run Code Online (Sandbox Code Playgroud)
a_1, a_2, ..., a_n
剩下的待切割地点的排列在哪里.我们必须将所有可能的排列传递给递归函数,而不仅仅是我写过的那个.
这显然是不切实际的.我该如何解决这个问题?
另一种DP解决方案:
让我们的COST(a,b)是切割第a个和第b个切割点之间的线段的最佳成本。显然,COST(a,a)和COST(a,a + 1)为零。我们可以计算出COST(a,b)的最佳值,因为它是对所有中间点a + 1 ... b-1加上自己的线段长度的最小切割。因此,我们可以用对角线填充对角线三角形表,并以O(N ^ 3)时间复杂度和O(N ^ 2)空间找到最终结果作为COST(start,end)
Delphi代码(输出Cost 20 Sequence 4 2 7
)
var
Cuts: TArray<Integer>;
Cost: array of array of Integer;
CutSequence: array of array of String;
N, row, col, leftpos, rightpos, cutpos, Sum: Integer;
begin
Cuts := TArray<Integer>.Create(0, 2, 4, 7, 10); // start, cuts, end points
N := Length(Cuts);
SetLength(Cost, N, N); //zero-initialized 2D array
SetLength(CutSequence, N, N); //zero-initialized 2D array
for rightpos := 2 to N - 1 do
for leftpos := rightpos - 2 downto 0 do begin //walk along the diagonals
//using previously computed results
//find the best (mincost) cut
Cost[leftpos, rightpos] := MaxInt; //big value
for cutpos := leftpos + 1 to rightpos - 1 do begin
Sum := Cost[leftpos, cutpos] + Cost[cutpos, rightpos];
if Sum < Cost[leftpos, rightpos] then begin
Cost[leftpos, rightpos] := Sum;
//write down best sequence
CutSequence[leftpos, rightpos] := Format('%d %s %s', [Cuts[CutPos],
CutSequence[leftpos, cutpos], CutSequence[cutpos, rightpos]]);
end;
end;
//add own length
Cost[leftpos, rightpos] :=
Cost[leftpos, rightpos] + Cuts[rightpos] - Cuts[leftpos];
end;
//show the best result
Caption := Format('Cost %d Sequence %s',[Cost[0, N-1], CutSequence[0, N-1]]);
Run Code Online (Sandbox Code Playgroud)