0%

动态规划问题

钢条切割

问题描述

钢条切割问题是这样的:给定一段长度为n英寸的钢条和一个价格表 $p_{i} (i=1,2,\ldots,n)$ ,求切割钢条方案,使得销售$r_{n}$收益最大。注意,如果长度为n英寸的钢条的价格$p_{n}$足够大,最优解可能就是完全不需要切割

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
using namespace std;

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

int Memorized_Cut_Rod_Aux(int p[], int n, int r[]) // “备忘”递归
{
if (r[n] >= 0)
return r[n];
int profit = 0;
if (n == 0)
profit = 0;
else
{
profit = -1;
for (int i = 1; i <= n; i++)
profit = max(profit, p[i] + Memorized_Cut_Rod_Aux(p, n - i, r));
}
r[n] = profit;
return r[n];
}

int Bottom_Up_Rod(int p[], int n) // 自底向上
{
int r[n];
memset(r, 0, sizeof(r));
for (int j = 1; j <= n; j++)
{
int profit = -1;
for (int i = 1; i <= j; i++)
profit = max(profit, p[i] + p[j - i]);
r[j] = profit;
}
return r[n];
}

int main()
{
int p[11] = {0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30};
int r[50];
memset(r, -1, sizeof(r));
cout << Memorized_Cut_Rod_Aux(p, 10, r) << endl;
cout << Bottom_Up_Rod(p, 10) << endl;
return 0;
}

扩展

下面给出的是 BOTTOM-UP-CUT- ROD的扩展版本,它对长度为 j 的钢条不仅计算最大收益值$r_{j}$,还保存最优解对应的第一段钢条的切割长度$s_{j}$:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int Extented_Bottom_Up_Rod(int p[], int n, int *r, int *s)
{
r[0] = 0;
for (int j = 1; j <= n; j++)
{
int profit = -1;
for (int i = 1; i <= j; i++)
{
if (profit < p[i] + p[j - i])
{
profit = p[i] + p[j - i];
s[j] = i;
}
}
r[j] = profit;
}
return r[n];
}

时间复杂度

自底向上与“备忘”递归两种方法的时间复杂度同阶,自底向上的方法由于没有递归的消耗,在常数因子上优于“自底向上”的方法

两种方法的时间复杂度均为:$T(n) = \Theta(n^{2})$