动态规划之钢条切割(算法导论)

1、问题描述

对于不同长度的钢条,其价格各不相同,现给定一个钢条的价格表,以及长度为n的钢条,求如何切割这个长度为n的钢条,使得价值最大。


2样例分析

假如现在给定一价格表如下:

1 2 3 4 5 6 7 8 9 10

1 5 8 9 10 17 17 20 24 30

现有一个长度为4的钢条,如何切割才能使得价值最大?

总共有三种切割方案,分别为:

10+4,价值为9.

21+3,价值为1+8=9.

32+2,价值为5+5=10.

所以,切割方案为2+2时,所获得的价值最大。


3问题解析

对于长度为n的钢条,假设最佳的切割点为:k,(1<k<=n.这时,将原问题转化成了两个规模更小的子问题,子问题的规模分别为:kn-k。原问题的最优解切割方案依赖子问题的最优切割方案。然后依次找出子问题,子子问题的最优切割方案。

为了使问题变得更加简化,我们每次从钢条的左端切去长度为i的钢条,然后对剩下的长度为n-i的钢条继续进行切割。此时,对切下的长度为i的钢条不再进行切割,只对n-i进行切割。

在此,又有两种思路:

1)自顶向下的递归方案。每次在钢条的左侧切下长度为k的钢条,然后对右侧长度为n-k的钢条继续进行递归,找出最优的切割方案。这种方法存在一个问题,就是会反复求解相同的子问题。这时,需要将已经计算出的子问题结果进行保存,当下次需要求解相同子问题时,不需要重新进行计算。

2)自底向上的切割方案。依次计算长度为1,2,3,...,n的最优切割方案,第n次的最优切割方案,依赖于前n-1次的最优切割方案。


4、算法实现

对于以上的两种思路,分别将其进行了实现。其中函数CutSteel1使用自顶向下的递归方案来实现钢条的最优切割,而函数CutSteel2使用自底向上的钢条切割方案。两种方案的时间复杂度都为O(n2).

<span style="font-size:18px;">/**
  钢条切割问题
  给出一个价格表,如下:
  	1	2	3	4	5	6	7	8	910		(m = 10)
	1	5	8	9	10	17	17	20	24	30
  现有长度为n的钢条,求如何切割才能使得价值最大。

  **/
#include <stdio.h>
#include <string.h>
int price[1002];
//up --> bottom
int cutSteel1(int n, int r[], int s[])		//return the maxValue
{
	int i, tmp, hel, ss;
	if(r[n] >= 0)
		return r[n];
	if(0 == n)
	{
		tmp = 0;
	}
	else 
	{
		for(i=1; i<=n; i++)
		{
			if(1 == i){
				tmp = price[i]+cutSteel1(n-i, r, s);
				ss = i;
			}
			else{
				hel = price[i] + cutSteel1(n-i, r, s);
				if(tmp < hel)
				{
					tmp = hel;
					ss = i;
				}
			}
		}
		s[n] = ss;
	//	r[n] = tmp;
	}
	r[n] = tmp;
	return r[n];
}
//bottom --> up
int cutSteel2(int n, int r[], int s[])
{
	int i, j, tmp, hel, ss;
	r[0] = 0;
	s[1] = 1;
	
	for(i=1; i<=n; i++)
	{
		tmp = price[1]+r[i-1];
		ss = 1;
		for(j=2; j<=i; j++)
		{
			hel = price[j]+r[i-j];
			if(tmp < hel)
			{
				tmp = hel;
				ss = j;
			}
		}
		s[i] = ss;
		r[i] = tmp;
		
	}
	return r[n];
}
void print(int n, int s[])
{
	int i;
	printf("切割方案: ");
	for(i=n; i>0; i=i-s[i])
		printf("%d\t", s[i]);
	printf("\n\n");
}
int main()
{
	freopen("in.test", "r", stdin);
	int m, n;
	int i, maxValue;
	int r[1002], s[1002];
	// input the price table
	memset(price, 0, sizeof(price));
	scanf("%d", &m);
	for(i=1; i<=m; i++)
		scanf("%d",&price[i]);
	
	//input the length n
	while(scanf("%d", &n)==1)
	{
		memset(r, 0xffffffff, sizeof(r));
		memset(s,0,sizeof(s));
		maxValue = cutSteel1(n, r, s);
		//maxValue = cutSteel2(n, r, s);
		printf("n=%d, maxValue = %d\n", n, maxValue);
		print(n, s);
	}
	
	return 0;
}</span>




转载于:https://www.cnblogs.com/liuwu265/p/4032127.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值