小白进阶之动态规划-钢条切割

本文深入探讨动态规划算法,强调最优子结构和重复子问题的重要性。通过四个步骤解释动态规划的设计过程,并以钢条切割问题为例进行详细阐述。文章提供了问题的递归定义、自底向上的解决方案,以及价格表和两种求解方法:带备忘的自顶向下和自底向上。最后,给出了问题的程序源码片段。
摘要由CSDN通过智能技术生成

关于动态规划算法,首先是:

什么样子的问题适合用动态规划算法来解呢?

适合用动态规划算法解的问题应具有两个性质:最优子结构性质和具有重复子问题

最优子结构性质是指:若一个问题的最优解包含其子问题的最优解,则此问题具有最优子结构性质。

具有重复子问题性质是指:问题的递归算法会反复求解相同的子问题。

然后是:

动态规划算法的设计有四个步骤:

1.刻画一个最优解的结构特征-寻找最优子结构;

2.递归地定义最优解的值;

3.计算最优解的值,通常采用自底向上的方法;

4.利用计算出的信息构造一个最优解。

动态规划算法有4个经典问题:钢条切割、矩阵链乘法、最长公共子序列、最优二叉搜索树。

本文会解决钢条切割问题,其他问题会后面的文章中解决。

钢条切割

给定一段长度为n英寸的钢条和一个价格表,求切割钢条的方案,使受益最大。

求解方法:将钢条从左边切下长度为i的一段,只对右边剩下的长度为n-i的一段继续切。

价格表如下:

长度i12345678910
价格p[i]1589101717202430
动态规划求解有两种方法:带备忘的自顶向下法和自底向上法,期望运行时间都为:θ(n²)。

(1)带备忘的自顶向下法:按照递归形式编写过程,但过程中会保存每一个子问题的解。当需要一个子问题的解时,过程首先检查是否已经保存过此解,若是则返回保存的值。

(2)自底向上法:当求解其子问题时,它所依赖的那些更小的子问题都已经求解完毕并且结果已经保存。

下面就贴程序源码了:

rodCutting.h:

#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
int memoizedCutRod(int *p,int n,int *r);//带备忘的自顶向下法
int extendedBottomUpCutRod(int *p,int n,int *r,int *s);//扩展的自底向上法
void printCutRodSolution(int *p,int n);//打印结果

rodCutting.cpp
#include"rodCutting.h"
int memoizedCutRodAux(int *p,int n,int *r);
int memoizedCutRod(int *p,int n,int *r){
	int i;
	for(i=0;i<n+1;i++)
		r[i]=INT_MIN;
	return memoizedCutRodAux(p,n,r);
}
int memoizedCutRodAux(int *p,int n,int *r){
	int q,i;
	if(r[n]>=0)
		return r[n];
	if(n==0)
		q=0;
	else{
		q=INT_MIN;
		if(n<11){
			for(i=1;i<n+1;i++){
				int t=p[i]+memoizedCutRodAux(p,n-i,r);
				if(q<t){
					q=t;
				}
			}
		}
		else{
			for(i=1;i<11;i++){
				int t=p[i]+memoizedCutRodAux(p,n-i,r);
				if(q<t){
					q=t;
				}
			}
		}
	}
	r[n]=q;
	return q;
}
int extendedBottomUpCutRod(int *p,int n,int *r,int *s){
	r[0]=0;
	int i,j,q;
	for(j=1;j<n+1;j++){
		q=INT_MIN;
		if(j<11){
			for(i=1;i<=j;i++){
				if(q<p[i]+r[j-i]){
					q=p[i]+r[j-i];
					s[j]=i;
				}
			}
		}
		else{
			for(i=1;i<11;i++){
				if(q<p[i]+r[j-i]){
					q=p[i]+r[j-i];
					s[j]=i;
				}
			}
		}
		r[j]=q;
	}
	return r[n];
}
void printCutRodSolution(int *p,int n){
	int *r,*s;
	r=(int *)malloc(sizeof(int)*(n+1));
	s=(int *)malloc(sizeof(int)*(n+1));
	int q;
	q=extendedBottomUpCutRod(p,n,r,s);
	printf("The max income is:%d\n",q);
	printf("The solution of the max income is:\n");
	while(n>0){
		printf("%d ",s[n]);
		n=n-s[n];
	}
}

main.cpp:
#include"rodCutting.h"
int main(){
	int p[11]={0,1,5,8,9,10,17,17,20,24,30};
	int n,i;
	printf("Please input the length of the rod:\n");
	scanf("%d",&n);
	int *r;
	r=(int *)malloc(sizeof(int)*(n+1));
	int q;
	q=memoizedCutRod(p,n,r);
	printf("The maximum income is:%d\n",q);
	printf("Every little income is:\n");
	for(i=0;i<n+1;i++){
		printf("%d-%d ",i,r[i]);
	}
	printf("\n");
	printCutRodSolution(p,n);
	system("pause");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值