• 钢条切割问题


    问题描述:假设公司出售长度为i的钢条价格为pi,如下价格表:

    长度i 1 2 3 4 5 6 7 8 9 10
    价格pi 1 5 8 9 10 17 17 20 24 30

      给一个n长度钢条和一个价格表,求切割方案使得总收益最大。

    分析:当问题长度为n时候,每隔一米有两种选择(切或者不切),从而切割方案有2n种,如果用暴力来求解,复杂度会达到指数次方,比如一个长度为4的钢条可以有以下切割方案:

    (1)4=1+1+1+1(2)4=1+3(3)4=2+2(4)4=3+1(5)4=1+1+2(6)4=1+2+1(7)4=2+1+1(8)4=4;

    比较刻字方案(3)的收益最高为10,从而方案(3)为最佳切割方案。

    为啦求解规模为n的问题,我们可以求解问题一样但是规模更小的问题,当我们完成首次切割后,我们将剩下钢条看做两个独立的钢条切割问题,我们通过求解两个子问题最优解来构造原问题最优解,及说明此问题

    有最优最结构的性质:我们将钢条从左切割下长度为i的一段,只对右边长度为n-i的一段进行继续切割,问题分解方式为:将问题从左边切割下一段,将右边部分继续做相同的分解,若剩余长度为0则收益也为0,

    Rn=max{p[i]+R[n-i]}(1=<i<=n);

    方法1,自顶向下:

    int CutRod(int price[], int *r, int n){
    int q =price[n],i,t; //设计q初始化为不切割情况
    if (r[n] >= 0)//所有r[1...n]都初始为负数,若此次不是负数,说明已经计算过,不用在计算,从而节省啦大量时间
        return r[n]; //如果计算过直接返回
    else{
    for (i =1; i <n; i++){
    t =price[i]+CutRod(price, r,n-i); //子问题的解
    if (q < t)
    q = t;
    }
    }
    r[n] = q; //该问题的解
    cout << n << " : " << r[n] << endl;       //输出当前长度下的造价收益
    return q;
    }

    该问题中通过判断r[i](1<=i<=n)是否大于0来判断r[i]是否有计算过,如果计算过就不用重新计算,这样大大提高啦运行效率,保准啦每个子问题只计算一次.

    方法2:自底向上:

    int CutRod2(int price[], int *r, int n){
    int q,i,j,t;
    r[0] = 0; //长度为0的钢条收益为0
    for (i = 1; i <=n; i++){
    q = -1; //初始为负数
    for (j = 1; j <= i; j++){
    t = price[j] + r[i - j]; //计算长度为i的钢条的切割方案收益
    if (t>q)
    q = t;
    }
    r[i] = q; //计算完长度为i的钢条的造价收益保存
    }
    return q;
    }

    两种代码的时间复杂度都是O(n2).如果要重构解的问题,输出具体的切割方案,则还需要一个数组s[n]来保存切割方案:

    int *CutRod2(int price[], int *r, int n){
    int q,i,j,t;
    r[0] = 0; //长度为0的钢条收益为0
    for (i = 1; i <=n; i++){
    q = -1; //初始为负数
    for (j = 1; j <= i; j++){
    t = price[j] + r[i - j]; //计算长度为i的钢条的切割方案收益
    if (t>q)
    q = t;
    }
    r[i] = q; //计算完长度为i的钢条的造价收益保存
    }
    return s;
    }

    如果要构造问题解的方案,这需要一个数组s[n]来保存切割的位置:

    //----钢条切割2,动态规划
    #include<iostream>
    #include<fstream>
    using namespace std;
    int CutRod2(int price[], int *r,int*s ,int n);
    int main(){
    ifstream sin("a.txt");
    int n, i, price[100], r[1000],s[1000];
    sin >> n;
    for (i = 1; i < n + 1; i++)
    sin >> price[i];
    int R = CutRod2(price, r,s, n);
    for (i = 0; i <= n; i++)
    cout << i << " :" << r[i] << endl;
    n = 9;      //输出长度为9的钢条切割方案
    while (s[n]>0){
    cout << s[n] << " ";
    n = n - s[n];
    }
    return 0;
    }
    int CutRod2(int price[], int *r,int *s, int n){
    int q,i,j,t;
    r[0] = 0; //长度为0的钢条收益为0
    for (i = 1; i <=n; i++){
    q = -1; //初始为负数
    for (j = 1; j <= i; j++){
    t = price[j] + r[i - j]; //计算长度为i的钢条的切割方案收益
    if (t > q){
    q = t;
    s[i] = j; //保存长度为i的钢条第一次切割的长度
    }
    }
    r[i] = q; //计算完长度为i的钢条的造价收益保存
    }
    return q;
    }

  • 相关阅读:
    配置Kickstart无人值守安装centos5.9 天高地厚
    数据库是什么,它是做什么用的? 天高地厚
    Mysql主从复制 天高地厚
    android开发中eclipse里xml的自动提示
    "error: device not found" and "error:device offline"
    gentoo中emerge失效:File "/usr/bin/emerge", line 43
    android:修改preference中view属性
    gerrit上利用sshkeygen公钥
    git 基本命令介绍
    prebuilt/linuxx86/toolchain/armeabi4.4.3/bin/armeabigcc: /lib/libc.so.6: version `GLIBC_2.11' not found:解决办法
  • 原文地址:https://www.cnblogs.com/td15980891505/p/4934259.html
Copyright © 2020-2023  润新知