动态规划——钢管切割最小代价问题

一、问题描述:

设有一根长度为L的钢条,在钢条上标有n个位置点(p1,p2,......,pn)。现在需要按钢条上标注的位置将钢条切割为n+1段,每次切割的代价为所切的钢条长度,试求在所有的切割方案中的总代价的最小值。

二、问题分析:

这是一道利用动态规划算法解决的问题,原因如下:(1)该问题具有最优子结构性质。当我们确定第一次切割的点时,切割后形成的两根小钢管也应按照最小的代价切割,否则我们拿最小代价的切割方案来代替现有切割方案,整根钢管切割的总代价将会减小,这就会产生矛盾。(2)该问题具有重叠子问题。相同的子问题会在我们确定不同切割点的时候反复出现。

三、递推关系:

我们来考察在位置点pi到位置点pj之间进行切割的情况,cost[i][j]为这个问题的总代价(i=1,2,......,n ; j=1,2,......,n),那么:

当i>j时,不需要切割:cost[i][j]=0;

当i=j时,仅有一个切割点:cost[i][j]=d(i+1)-d(i-1);

当i<j时,有多个切割点:cost[i][j]=min{cost[i][k-1]+cost[k+1][j]+d(j+1)-d(i-1)};其中k=i,i+1,......,j。

四、完整代码:

#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
	int L,n;//L为完整钢管总长度,n为切割点的数目
	cout<<"请输入钢管总长度和切割点数目:";
	cin>>L>>n; 
	int *p;//记录n个切割点位置坐标的数组
	p=new int[n+2];//多出来的2是钢管的左端点(起点)和右端点(终点)
	p[0]=0;p[n+1]=L;//将左端点视为原点
	int i,j,step;//i,j为简单的循环所需变量,step为i,j之间的步长 
	for(i=1;i<=n;i++)
	{
		cout<<"请输入第"<<i<<"个切割点的位置坐标:" ; 
		cin>>p[i];
	}
	sort(p,p+n+2);//将坐标从小到大排列
	int **cost=new int*[n+2];
	for(i=0;i<n+2;i++)
	{
		cost[i]=new int[n+2];
	}//动态创建二维数组,cost[i][j]的意义见递推关系解释
	for(i=0;i<n+2;i++)
	{
		for(j=0;j<n+2;j++)
		{
			if(i>j)
			{
				cost[i][j]=0;
			}
			else if(i==j && i!=0 && i!=n+1)//这些限制条件防止数组超界 
			{
				cost[i][j]=p[i+1]-p[i-1];
			}
		}
	}
	cost[0][0]=0;cost[n+1][n+1]=0;//额外初始化
	for(step=1;step<=n-1;step++)
	{
		for(i=1;i<=n;i++)
		{
			j=i+step;
			int CutPoint=i;//定义切点 
			int MyCostMin=cost[i][CutPoint-1]+cost[CutPoint+1][j]+(p[j+1]-p[i-1]);//定义最小代价 
			for(CutPoint=i+1;CutPoint<=j;CutPoint++)
			{
				if(j<n+1)//防止数组越界 
				{
					int PreCost=cost[i][CutPoint-1]+cost[CutPoint+1][j]+(p[j+1]-p[i-1]);//定义当前代价 
					if(PreCost<MyCostMin)
					{
						MyCostMin=PreCost;
					}
				}
			}
			cost[i][j]=MyCostMin;
		}
	}
	cout<<"需要的最小总代价为:"<<cost[1][n];
}

五、运行结果:

 

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值