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


    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	", s[i]);
    	printf("
    
    ");
    }
    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, maxValue);
    		print(n, s);
    	}
    	
    	return 0;
    }</span>




  • 相关阅读:
    修改profile出错后的补救
    ubuntu安装jdk
    创业的36条军规
    Oracle中慎用Like等通配符
    根据配置文件名读取配置文件的工具类方法
    Spring ThreadPoolTaskExecutor队列满的异常处理
    redis使用方法
    在windows 2008 R2中SQl Server 2008中代理启动失败的一个原因总结
    select 中添加option的注意
    javascript 函数对象
  • 原文地址:https://www.cnblogs.com/liuwu265/p/4032127.html
Copyright © 2020-2023  润新知