• [置顶] 动态规划之切割钢条


    假设公司出售一段长度为i英寸的钢条的价格为Pi(i = 1, 2, ...单位:美元),下面给出了价格表样例:

    长度i     1     2     3  4  5  6     7  8  9  10

    价格Pi  1     5     8  9  10  17   17  20  24  30

    切割钢条的问题是这样的:给定一段长度为n英寸的钢条和一个价格表Pi,求切割方案,使得销售收益Rn最大。

    当然,如果长度为n英寸的钢条价格Pn足够大,最优解可能就是完全不需要切割。

    对于上述价格表样例,我们可以观察所有最优收益值Ri及对应的最优解方案:

    R1 = 1,切割方案1 = 1(无切割)

    R2 = 5,切割方案2 = 2(无切割)

    R3 = 8, 切割方案3 = 3(无切割)

    R4 = 10, 切割方案4 = 2 + 2

    R5 = 13, 切割方案5 = 2 + 3

    R6 = 17, 切割方案6 = 6(无切割)

    R7 = 18, 切割方案7 = 1 + 6或7 = 2 + 2 + 3

    R8 = 22, 切割方案8 = 2 + 6

    R9 = 25, 切割方案9 = 3 + 6

    R10 = 30,切割方案10 = 10(无切割)

    更一般地,对于Rn(n >= 1),我们可以用更短的钢条的最优切割收益来描述它:

    Rn = max(Pn, R1 + Rn-1, R2 + Rn-2,...,Rn-1 + R1)

    首先将钢条切割为长度为i和n - i两段,接着求解这两段的最优切割收益Ri和Rn - i

    (每种方案的最优收益为两段的最优收益之和),由于无法预知哪种方案会获得最优收益,

    我们必须考察所有可能的i,选取其中收益最大者。如果直接出售原钢条会获得最大收益,

    我们当然可以选择不做任何切割。

    分析到这里,假设现在出售8英寸的钢条,应该怎么切割呢?

    代码如下:

    package 动态规划;
    
    /**
     * 钢条不同长度价格不同,求如何切割钢条卖出最划算
     * 用到动态规划
     * @author wangdong20
     *
     */
    
    public class Steel {
    	/**
    	 * 自底向上非递归方法解决钢条切割问题,
    	 * 不仅保存最优收益值,还保存对应的切割方案
    	 * @param p 不同长度钢条的价格
    	 * @param n 钢条的总长度
    	 */
    	public static int[][] extendedBottomUpCutRod(int[] p, int n){
    		/*if(n == 0){
    			return new int[][]{
    					{0}, {0}};
    		}*/
    		int[][] s = new int[2][n + 1];  // s[0][2]保存2米长钢条的最佳收益,s[1][2]保存2米长钢条的切割方案
    		s[0][0] = 0;
    		
    		for(int j = 1; j <= n; j++){
    			int q = -99999;
    			for(int i = 1; i <= j; i++){
    				if(q < p[i] + s[0][j - i]){
    					q = p[i] + s[0][j - i];
    					s[1][j] = i;
    				}
    			}
    			s[0][j] = q;
    		}
    		System.out.print("
    最终受益: " + s[0][n]);
    		return s;
    	}
    	
    	/**
    	 * 根据算法打印出长度为n的钢条完整的最优切割方案
    	 * @param p 不同长度钢条的价格
    	 * @param n 钢条的总长度
    	 */
    	public static void printCutRodSolution(int[] p, int n){
    		int result[][] = extendedBottomUpCutRod(p, n);
    		System.out.print("
    钢板切除方案: ");
    		while(n > 0){
    			System.out.print(result[1][n] + " ");
    			n = n - result[1][n];
    		}
    	}
    
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) {
    		// TODO 自动生成方法存根
    //		 钢条的价格price[0]表示0米长钢条的价格,price[5]代表5米长钢条的价格
    		int price[] = {0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30};
    		
    		System.out.println("The price: ");
    		for(Integer i : price){
    			System.out.print(i + " ");
    		}
    		
    		printCutRodSolution(price, 8);
    	}
    
    }
    


    运行结果如下:

    The price: 
    0 1 5 8 9 10 17 17 20 24 30 
    最终受益: 22
    钢板切除方案: 2 6 

  • 相关阅读:
    Tribonacci UVA 12470 (简单的斐波拉契数列)(矩阵快速幂)
    P1091 合唱队形
    P1481 魔族密码 (LIS)
    xiaowuga poj3735—Training little cats(特殊操作转化为矩阵操作)
    P2665 [USACO08FEB]连线游戏Game of Lines
    1875 丢手绢 (模拟+打表)
    Recurrences UVA 10870 (斐波拉契的一般形式推广)
    Choosing number ZOJ 3690 (矩阵快速幂)
    根据屏幕文件生成RPG代码的思路
    基于配置文件的查询,xml文件sample
  • 原文地址:https://www.cnblogs.com/riskyer/p/3331310.html
Copyright © 2020-2023  润新知