15.1-1 由公式(15.3)和初始条件T(0) = 1,证明公式(15.4)成立。
ANSWER:
15.1-2 举反例证明下面的“贪心”策略不能保证总是得到最优切割方案。定义长度为i的钢条的密度为Pi / i,即每英寸的价值。贪心策略将长度为n的钢条切割下长度为i (1 ≤ i ≤ n)的一段,其密度最高。接下来继续使用相同的策略切割长度为n-i的剩余部分。
ANSWER:当长度n = 4时,按照“贪心”策略则切割成长度为1和3的钢条(p = 1 + 8 = 9);而最优解为切割成2条长度为2的钢条(p = 5 + 5 = 10 > 9)。
15.1-3 我们对钢条切割问题进行一点修改,除了切割下的钢条段具有不同价值Pi外,每次切割还要付出固定的成本c。这样,切割方案的收益就等于钢条段的价格之和减去切割成本。设计一个动态规划算法解决修改后的钢条切割问题。
ANSWER:多新建一个数组m[0...n]记录每个长度的钢条最优解的切割段数,当完成长度为i的钢条最优解时,更新长度为i+1时使m[i+1] = m[j] + 1,其中长度为i+1的钢条切割成长度为(i+1-j)和j的两大段,长度为j的钢条继续切割。
- let r[0...n] and m[0...n] be new arrays
- r[0] = 0, m[0] = 0
- for i = 1 to n
- q = -∞
- for j = 1 to i
- if q < p[j] + r[i-j] - m[i-j]*c
- q = p[j] + r[i-j] - m[i-j]*c
- m[i] = m[i-j] + 1
- r[i] = q
- return r[n]
//15.1-3带有固定切割成本的钢条切割方案 #if 0 #include <iostream> using namespace std; int Max(int a,int b) { return a>b?a:b; } struct array { int r;//代表最大收益 int s;//代表切割方案 }; struct array *EXTENDED_BOTTOM_UP_CUT_ROD(int p[],int n) { struct array *rs=new struct array[n]; rs[0].r=0; int q; for (int j=0;j<n;j++) { int flag=1;//哨兵为1代表无切割。 q=p[j]; for (int i=0;i<j;i++) { //q=Max(q,p[i]+rs[j-i].r-1); if(q<=p[i]+rs[j-i].r-1)//切割固定成本c=1 { q=p[i]+rs[j-i].r-1; rs[j+1].s=i+1; flag=0;//哨兵为0代表有切割。 } } if (j==i)//i=j代表无切割 { if (q<=p[i]+rs[j-i].r&&flag) {//无切割时注意切割方案就等于钢条长度。 rs[j+1].s=i+1; } } rs[j+1].r=q; } return rs+n; } void PRINT_CUT_ROD_SOLUTION(int p[],int n) { struct array *rs=EXTENDED_BOTTOM_UP_CUT_ROD(p,n); while (n>0) { cout<<(*rs).s<<" "; n=n-(*rs).s; rs=rs-(*rs).s; } } void main() { const int n=10; int p[10]={1,5,8,9,10,17,17,20,24,30}; cout<<(*EXTENDED_BOTTOM_UP_CUT_ROD(p,10)).r<<endl; PRINT_CUT_ROD_SOLUTION(p,10); }