动态规划--链条切割问题

   钢条切割问题:给定一段长度为n英寸的钢条和一个价格表pi(i=1,2,...,n)求切割钢条方案,使得销售收益rn最大。

    注意,如果长度为n英寸的钢条的价格pn足够大,最优解可能就是完全不需要切割。

       思路:先将钢条切成两条,有n-1种方案,每一种方案的最优解都等于两个子钢条的最优解。我们从这n-1个伪最优解再挑出最优的解了

       以下是伪代码:

1 CUT-ROD(p,n)

2 if n == 0

3     return 0

4 q=负无穷

5 for i = 1 to n

6     q=max(q,p[i]+CUT-ROD(p,n-i))

7 return q

上面只用了分治策略,这个算法的性能是很差的T(n)=2n,在子问题的求解中很多都是重复的。

动态规划就是避免这些重复。一般有两个思路1.记录中间解 

 1 MEM-CUT-ROD

 2 let r[0..n] be a new array

 3 for i = 0 to n

 4     r[i]=负无穷

 5 return MEM-CUT-ROD-AUX(p,n,r)

 6

 7 MEM-CUT-ROD-AUX(p,n,r)

 8 if r[n]>=0

 9     return r[n]

10 if n==0

11     q=0

12 else q=负无穷

13     for i=1 to n

14         q=max(q,p[i]+MEM-CUT-ROD-AUX(p,n-i,r))

15 r[n]=q

16 return q

 2.通过对问题求解顺序的合理安排,达到避免重复

1 BOTTOM-UP-CUT-ROD(p,n)

2 let r[0..n] be a new array

3 r[0]=0

4 for j=1 to n

5     q=负无穷

6     for i=1 to j

7         q=max(q,p[i]+r[j-i])

8     r[j]=q

9 return r[n]

下面的伪代码还保留了切割长度

 1 EXTEND-BOTTOM-UP-CUT-ROD(p,n)

 2 let r[0..n] and s[0..n] be new arrays

 3 r[0]=0

 4 for j = 1 to n

 5     q=负无穷

 6     for i =1 to j

 7         if q < p[i]+r[j-i]

 8             q=p[i]+r[j-i]

 9             s[j]=i

10             r[j]=q

11 return r and s

12

13 PRINT-CUT-ROD-SOLUTION(p,n)

14 (r,s)=EXTEND-BOTTOM-UP-CUT-ROD(p,n)

15 while n >0

16     print s[n]

17     n=n-s[n]

使用动态规划方法求解的最优化问题应该具备两个要素:最优子结构和子问题重叠

c语言实现代码;

#define MinNum -200
#define MaxNum 20
#include<stdio.h>
#include<stdlib.h>
int Max(int a, int b)
{
    return a > b ? a : b;
}
int CUT_ROD(int p[],int n)
{
    int q;
    if(n == 0)
        return 0;
    q = MinNum;
    for(int i = 1 ; i <= n; i++)
    {
        q = Max(q,p[i] + CUT_ROD(p,n-i));
    }
    return q;
}
int Bottom_UP_ROD(int p[],int n , int r[])
{
    int q;
    for(int i = 1; i <= n ; i++)
        r[i] = MinNum;
    r[0] = 0;
    for(int j = 1; j <= n ; j++)
    {
        q = MinNum;
        for(int i = 1 ; i <= j ;i++)
        {
            q = Max(q,p[i] + r[j-i]);
        }
        r[j] = q;
    }
    return r[n];
}
int MEMOIZED_CUT_ROD_AUX(int p[],int n , int r[])
{
    int q;
    if(r[n] >= 0)
        return r[n];
    if(n == 0)
         q = 0;
    else
    {
        q = MinNum;
        for(int i = 1 ; i <= n ; i++)
            q = Max(q,p[i] + MEMOIZED_CUT_ROD_AUX(p,n-i,r));
    }
    r[n] = q;
    return q;
}
void MEMOIZED_CUT_ROD(int p[],int n)
{
    int r[MaxNum];
    for(int i = 1 ; i <= n ; i++)
        r[i] = MinNum;
}
void EXTEND_DOWN_UP_ROD(int r[],int s[],int p[], int n)
{
    r[0] = 0;
    for(int j = 1 ; j <= n ;j++)
    {
        int q  = MinNum;
        for(int i =1 ; i <= j ; i++)
        {
            if(q < p[i] + r[j-i])
            {
                q = p[i] + r[j-i];
                s[j] = i;
            }
        }
        r[j] = q;
    }
}
void Print_CUT_ROD_SOLUTION(int p[], int n , int s[])
{
    printf("----------------------------------
");
    printf("长度为 %d 的切割方案为
",n);
    while(n > 0)
    {
        printf("%3d",s[n]);
        n = n - s[n];
    }
    printf("
");
}
int main()
{
    int p[] = {0,1,5,8,9,10,17,17,20,24};
    int r[MaxNum];
    int s[MaxNum];
    EXTEND_DOWN_UP_ROD(r,s,p,9);
    for(int i = 1; i <= 9; i++)
    {
        printf("长度为%d的收益最大为:%d
",i,r[i]);
    }
    Print_CUT_ROD_SOLUTION(p,9,s);
    system("pause");
    return 0;
}
原文地址:https://www.cnblogs.com/joyclub/p/4874972.html