您的位置:首页 > 其它

[算法]动态规划-钢条切割

2017-12-31 00:36 232 查看

钢条切割算法

某公司出售一段长度为i英寸的钢条的价格为p(i)如一次为{1,5,8,9,10,17,17,20,24,29},求给出一段长度为n的钢条,怎么切才能得到最佳收益?

对于这个问题,可以先切为两段,然后取最好的情况,第一段长度为i,则第二段为n-i,那么情况就有 i=1..n 共n种情况.

for(i=1;i<=n;i++)
{
q= maxmax(q, p(i)+cut_rod(n-i));
}


切除了i长,那么还剩n-i长,只需求出对n-i长的钢条如何切割,可以递归求解.

用递归算法来求解,时间复杂度为n^2,损耗较大

于是做了改进,将每次计算的结果保存下来,每次切割时如果已经有结果则不再计算.

int memorized_cut_rod_aux(int n,int * r)
{
int i;
int q=NEG_INF;  //设为负无穷
if (r
>=0) return r
;
if (n==0) return 0;
for(i=1;i<=n;i++)
{
q= maxmax(q, p(i)+cut_rod(n-i));
}
r
=q;
return q;
}

int memoized_cut_rod(int n)
{
int * r=(int*)malloc(sizeof(int)*(n+1));
int i;
int q=NEG_INF;
for(i=0;i<=n;i++)
{
r[i]=NEG_INF;
}
q=memorized_cut_rod_aux(n,r);
free(r);
return q;
}


上面的代码对递归算法做了改进,但是递归栈的调用损耗也比较大.

所以有进一步改进,所以有了从底向上法.由于n的切割必然需要n-1的切割,所以从1开始计算,并且每次计算时把结果保存起来.

时间复杂度为多项式级别

int bottom_up_cut_rod(n){
int * r=(int*)malloc(sizeof(int)*(n+1));
int i,j,q;
r[0]=0;
for(j=1;j<=n;j++)
{
q=NEG_INF;
for(i=1;i<=j;i++)
{
q=maxmax(q,p(i)+r[j-i]);
}
r[j]=q;
}
return r
;
}


再一次改进,加入了存储第一次切割的长度的功能,可以求出长度为n的钢条切割的切割路径.

`

//拓展的从底向上完成,可以存储第一次切割的长度

int extended_bottom_up_cut_rod(n){
int * r=(int*)malloc(sizeof(int)*(n+1));
int * s=(int*)malloc(sizeof(int)*(n+1));
int i,j,q,n2;
r[0]=0;
for(j=1;j<=n;j++)
{
q=NEG_INF;
for(i=1;i<=j;i++)
{
if(q<p(i)+r[j-i]){
q=p(i)+r[j-i];
s[j]=i;
}
}
r[j]=q;
}
n2=n;
printf("\n");
while(n2>0){
printf("%d",s[n2]);
n2-=s[n2];
if(n2>0) printf("->");
}
printf("\n");
return r
;
}


每次调用可以把路径打印输出

贴上完整代码

#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#define NEG_INF INT_MIN
#define MAXLEN 30

int s[MAXLEN+1];

int maxmax(int x,int y)
{
return x>y?x:y;
}

int p(int n)
{
const int p10[11]={0,1,5,8,9,10,17,17,20,24,29};
if(n<0) {
printf("error");
exit(-1);
}
return n/10*p10[10]+p10[n%10];
}

//递归切割钢条
int cut_rod(int n)
{
int i;
int q=NEG_INF;
if (n==0) return 0;
if (s
>0){
q=s
;
}else{
for(i=1;i<=n;i++)
{
q= maxmax(q, p(i)+cut_rod(n-i));
}
s
=q;
}
return q;
}

//递归切割,并存储结果
int memorized_cut_rod_aux(int n,int * r)
{
int i;
int q=NEG_INF;
if (r
>=0) return r
;
if (n==0) return 0;
for(i=1;i<=n;i++)
{
q= maxmax(q, p(i)+cut_rod(n-i));
}
r
=q;
return q;
}

int memoized_cut_rod(int n){
int * r=(int*)malloc(sizeof(int)*(n+1));
int i;
int q=NEG_INF;
for(i=0;i<=n;i++)
{
r[i]=NEG_INF;
}
q=memorized_cut_rod_aux(n,r);
free(r);
return q;
}

//从底向上完成
int bottom_up_cut_rod(n){ int * r=(int*)malloc(sizeof(int)*(n+1)); int i,j,q; r[0]=0; for(j=1;j<=n;j++) { q=NEG_INF; for(i=1;i<=j;i++) { q=maxmax(q,p(i)+r[j-i]); } r[j]=q; } return r ; }

//拓展的从底向上完成,可以存储第一次切割的长度

int extended_bottom_up_cut_rod(n){
int * r=(int*)malloc(sizeof(int)*(n+1));
int * s=(int*)malloc(sizeof(int)*
b43d
(n+1));
int i,j,q,n2;
r[0]=0;
for(j=1;j<=n;j++)
{
q=NEG_INF;
for(i=1;i<=j;i++)
{
if(q<p(i)+r[j-i]){
q=p(i)+r[j-i];
s[j]=i;
}
}
r[j]=q;
}
n2=n;
printf("\n");
while(n2>0){
printf("%d",s[n2]);
n2-=s[n2];
if(n2>0) printf("->");
}
printf("\n");
return r
;
}

int main()
{
int i;
for (i=0;i<=MAXLEN;i++){
s[i]=NEG_INF;
}

for (i=1;i<=MAXLEN;i++){
//printf("%d\t%d\n",i,cut_rod(i));
printf("%d\t%d\n",i,memoized_cut_rod(i));
printf("%d\t%d\n",i,bottom_up_cut_rod(i));

printf("%d\t%d\n",i,extended_bottom_up_cut_rod(i));
}

}


<算法导论> 第十五章 动态规划 15.1 钢条切割
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  动态规划 算法