文章目录

  • 前言
  • 一、钢条切割问题
    • 1.问题背景
    • 2.问题描述
    • 3.问题的难点
      • (1)情况较多
      • (2)消除重复子问题
  • 二、问题解决方案
    • 1.问题的特点
      • (1)最优化子结构
      • (2)重复子问题
    • 2.最优化解决方案
      • (1)自顶向下的普通递归
      • (2)带备忘的自顶向下
      • (3)自底向上
    • 3.构建最优解的结构
  • 三、C语言代码
    • 1.三种方案的函数代码
      • (1)自顶向下的普通递归
      • (2)带备忘的自顶向下
      • (3)自底向上
    • 2.整体测试代码
  • 总结

前言

本文主要讲解了钢条切割问题的解决方案,并且给出了C语言代码。其中涉及到了动态规划的思想,会在之后的文章中详细讲解


一、钢条切割问题

1.问题背景

Serling公司购买长钢条,将其切割成短钢条进行出售。切割工序本身没有成本支出。管理层希望得到最优的切割方法。
现在我们知道Serling公司出售一段长度为iii英寸的钢条的价格为pi(i=1,2,3,...,n)p_i(i=1,2,3,...,n)pi​(i=1,2,3,...,n),单位为美元。钢条的长度都为整英寸。

举例一个价格的样表如下:

长度iii 1 2 3 4 5 6 7 8 9 10
价格pip_ipi​ 1 5 8 9 10 17 18 20 24 30

2.问题描述

现在我们的问题是:

给定一段长度为n英寸n英寸n英寸的钢条和一个价格表pi(i=1,2,...,n)p_i(i=1,2,...,n)pi​(i=1,2,...,n),求切割钢条的方案,使得收益qqq最大化。

3.问题的难点

(1)情况较多

首先我们有如下结论:
长度为n英寸的钢条共有2n−1种不同的切割方案长度为n英寸的钢条共有2^{n-1}种不同的切割方案 长度为n英寸的钢条共有2n−1种不同的切割方案
具体的分析如下:

  • 对于长度为n英寸的钢条,我们有n-1个可切割点
  • 那么每个切割点的情况分为两种:切断或者不切断
  • 有n-1个点,每个点有两种情况

综上所述:总情况为2n−12^{n-1}2n−1

(2)消除重复子问题

我们可以试想以下,当我们想知道长度为7的钢条如何切割,会需要先解决一部分子问题,记为集合A。
而我们要解决长度为5英寸的钢条的子问题集为B
那么A与B肯定存在公共的子问题需要求解

那么这样看来,解决长度越长,包含更多的重复的子问题来浪费资源。

二、问题解决方案

1.问题的特点

(1)最优化子结构

首先该问题是求解一个最优化的问题。

其次我们可以将该最优化问题分解为诸多最优化的子问题来求解
举个例子
对于长度为4的问题,我们可以这样分割:
4的最优解=最优(1的价格+3的最优,2价格+2的最优,3的价格+1的最优<1的最优也便是1的价格>)4的最优解=最优(1的价格+3的最优,2价格+2的最优,3的价格+1的最优<1的最优也便是1的价格>) 4的最优解=最优(1的价格+3的最优,2价格+2的最优,3的价格+1的最优<1的最优也便是1的价格>)
可以发现该最优问题确实可以分解为诸多最优子问题来解决。
涉及到了子问题,这样我们就顺其自然地用递归等方法来解决问题。

(2)重复子问题

这里前文已经分析过。会有资源耗费在解决重复的子问题上。
那么我们需要想方案让这些子问题仅解决一次,这里就用到了动态规划的思想。
我们有两种具体的方案:

  • 带备忘的自顶向下
  • 自底向上

下文将进行具体讲解

2.最优化解决方案

(1)自顶向下的普通递归

该方案就是编程实现上文中将问题分解为子问题的过程。
采用递归的方式,遍历所有的情况。
最后时间复杂度将是可怕的O(2n)O(2^n)O(2n)

(2)带备忘的自顶向下

该方案对比普通的自顶向上的方案仅有一个改进之处
就是采用一个存储数组存储已经解决的子问题,如果下次遇到已经解决过的子问题,那么直接在存储数组中查找即可,节省了时间

(3)自底向上

该方案是先从最底层的子问题开始解决,接着向上一层解决高一层的子问题。
以此不断循环,最后将总体问题解决。

3.构建最优解的结构

我们现在得到了最大利润,但是如何得到最优的方案呢?
我们需要引入一个存储数组s,存储“切割的第一刀”

现在我们来理解什么是“切割的第一刀”,回想以下我们如何将长度4的问题进行切割的:
4的最优解=最优(1的价格+3的最优,2价格+2的最优,3的价格+1的最优<1的最优也便是1的价格>)4的最优解=最优(1的价格+3的最优,2价格+2的最优,3的价格+1的最优<1的最优也便是1的价格>) 4的最优解=最优(1的价格+3的最优,2价格+2的最优,3的价格+1的最优<1的最优也便是1的价格>)
对于上述的例子来说,可能的“切割的第一刀”有:1,2,3。
我们可以理解为,切割这个第一刀后,问题被分解为最优子问题。
因此我们需要存储所有问题的”第一刀“,然后就可以通过一个简单的循环找到具体的切割方案。

三、C语言代码

1.三种方案的函数代码

(1)自顶向下的普通递归

//返回最大值函数
int MAX(int a,int b)
{if(a>=b){return a;}else{return b;}
}
//自顶向下不加备忘机制
int CUT_ROD(int *p,int n,int size)
{int q=0;int i=0;if(n==0){return 0;}q=-10;if(n>=size){for(i=1;i<size;i++){q=MAX(q,p[i]+CUT_ROD(p,n-i,size));}  }else{for(i=1;i<=n;i++){q=MAX(q,p[i]+CUT_ROD(p,n-i,size));}}return q;
}

(2)带备忘的自顶向下

//返回最大值函数
int MAX(int a,int b)
{if(a>=b){return a;}else{return b;}
}
//自顶向下加备忘机制方法
int MEMORIZED_CUT_ROD_DO(int *p,int n,int *w,int *s,int size)
{int q=0;int i=0;if(w[n]>=0){return w[n];}q=-10;if(n>=size){for(i=1;i<size;i++){if(q<(p[i]+MEMORIZED_CUT_ROD_DO(p,n-i,w,s,size))){s[n]=i;q=p[i]+MEMORIZED_CUT_ROD_DO(p,n-i,w,s,size);}          }}else{for(i=1;i<=n;i++){if(q<(p[i]+MEMORIZED_CUT_ROD_DO(p,n-i,w,s,size))){s[n]=i;q=p[i]+MEMORIZED_CUT_ROD_DO(p,n-i,w,s,size);}           }       }w[n]=q;return q;
}
int MEMORIZED_CUT_ROD(int *p,int n,int *w,int *s,int size)
{int i=0;for(i=0;i<=n;i++){w[i]=-1;}w[0]=0;s[0]=0;return MEMORIZED_CUT_ROD_DO(p,n,w,s,size);
}

(3)自底向上

//返回最大值函数
int MAX(int a,int b)
{if(a>=b){return a;}else{return b;}
}
//自底向上的方法
int BOTTOM_UP_CUT_ROD(int *p,int n,int *w,int *s,int size)
{int q=0;w[0]=0;s[0]=0;int j=0;int i=0;for(j=1;j<=n;j++){q=-10;if(j>=size){for(i=1;i<size;i++){if(q<(p[i]+w[j-i])){s[j]=i;q=p[i]+w[j-i];}}            }else{for(i=1;i<=j;i++){if(q<(p[i]+w[j-i])){s[j]=i;q=p[i]+w[j-i];}}           }w[j]=q;}return w[n];
}

2.整体测试代码

#include<stdio.h>
#include<stdlib.h>
#include<time.h>//由于要存放长度为0时,钢条的价格为0
//因此市场上可以出售钢条长度为1~SIZE-1
//这SIZE-1种整数长度
//比如SIZE=5时
//钢条可以切成1,2,3,4
#define SIZE 6//输入规模 //钢条长度每增加一单位
//其价格增加LIM+1
//因此它是钢条价格的单位随机增量
#define LIM 7//随机数的范围:0~(LIM-1)//钢条的总长度
#define Length 10; //返回最大值函数
int MAX(int a,int b)
{if(a>=b){return a;}else{return b;}
} //自顶向下不加备忘机制
int CUT_ROD(int *p,int n,int size)
{int q=0;int i=0;if(n==0){return 0;}q=-10;if(n>=size){for(i=1;i<size;i++){q=MAX(q,p[i]+CUT_ROD(p,n-i,size));}  }else{for(i=1;i<=n;i++){q=MAX(q,p[i]+CUT_ROD(p,n-i,size));}}return q;
} //自顶向下加备忘机制方法
int MEMORIZED_CUT_ROD_DO(int *p,int n,int *w,int *s,int size)
{int q=0;int i=0;if(w[n]>=0){return w[n];}q=-10;if(n>=size){for(i=1;i<size;i++){if(q<(p[i]+MEMORIZED_CUT_ROD_DO(p,n-i,w,s,size))){s[n]=i;q=p[i]+MEMORIZED_CUT_ROD_DO(p,n-i,w,s,size);}          }}else{for(i=1;i<=n;i++){if(q<(p[i]+MEMORIZED_CUT_ROD_DO(p,n-i,w,s,size))){s[n]=i;q=p[i]+MEMORIZED_CUT_ROD_DO(p,n-i,w,s,size);}           }       }w[n]=q;return q;
}
int MEMORIZED_CUT_ROD(int *p,int n,int *w,int *s,int size)
{int i=0;for(i=0;i<=n;i++){w[i]=-1;}w[0]=0;s[0]=0;return MEMORIZED_CUT_ROD_DO(p,n,w,s,size);
}//自底向上的方法
int BOTTOM_UP_CUT_ROD(int *p,int n,int *w,int *s,int size)
{int q=0;w[0]=0;s[0]=0;int j=0;int i=0;for(j=1;j<=n;j++){q=-10;if(j>=size){for(i=1;i<size;i++){if(q<(p[i]+w[j-i])){s[j]=i;q=p[i]+w[j-i];}}            }else{for(i=1;i<=j;i++){if(q<(p[i]+w[j-i])){s[j]=i;q=p[i]+w[j-i];}}           }w[j]=q;}return w[n];
}//打印钢条的最优组合
void print_max(int *s,int n)
{int i=n-1;printf("价格最优情况下,钢条的长度组合之一如下:\n"); while(i>0){printf("%5d",s[i]);i=i-s[i];}printf("\n");
} //主函数
int main()
{int i=0;int maxp=0;int n=Length; int p[SIZE];int w[n+1];int s[n+1];srand((unsigned)time(NULL));int temp=0;for(i=0;i<SIZE;i++){p[i]=temp;temp=temp+rand()%LIM+1;}for(i=0;i<SIZE;i++){printf("%5d",p[i]);}printf("\n");//自顶向下不加备忘机制maxp=CUT_ROD(p,n,SIZE);printf("max profit is %5d\n",maxp);//自顶向下加备忘机制方法maxp=MEMORIZED_CUT_ROD(p,n,w,s,SIZE);printf("max profit is %5d\n",maxp);print_max(s,n+1);//自底向上的方法maxp=BOTTOM_UP_CUT_ROD(p,n,w,s,SIZE);printf("max profit is %5d\n",maxp);for(i=0;i<=n;i++){printf("%5d",w[i]);}printf("\n");print_max(s,n+1);return 0;
}

总结

文章不妥之处请各位读者包涵指正

《算法导论》学习(十七)----动态规划之钢条切割(C语言)相关推荐

  1. 算法导论15.1动态规划之钢条切割

    动态规划与钢条切割 1.分治算法与动态规划 相同点: 都是通过组合子问题的解来求解原问题 不同: 1.分治将问题划分为互不相交的子问题,递归地求解子问题,在将它们的解组合起来,求出原问题. 2.动态规 ...

  2. 《算法导论》中动态规划求解钢条切割问题

    动态规划算法概述 动态规划(dynamic programming)1是一种与分治方法很像的方法,都是通过组合子问题的解来求解原问题.不同之处在于,动态规划用于子问题重叠的情况,比如我们学过的斐波那契 ...

  3. 算法导论-动态规划(钢条切割问题)

    写下文章来记录下自己学习算法导论的笔记 文章目录 写下文章来记录下自己学习算法导论的笔记 动态规划的目的 设计动态规划算法 钢条切割问题 问题描述 刻画问题结构(建立方程) 递归方程建立 带备忘录的自 ...

  4. Python数据结构与算法-动态规划(钢条切割问题)

    一.动态规划(DP)介绍 1.从斐波那契数列看动态规划 (1)问题 斐波那契数列递推式: 练习:使用递归和非递归的方法来求解斐波那契数列的第n项 (2)递归方法的代码实现 import time # ...

  5. 【算法导论学习-29】动态规划经典问题02:最长公共子序列问题(Longest common subsequence,LCS)...

    2019独角兽企业重金招聘Python工程师标准>>> 问题描述:序列X={x1,x2,-,xn},Y={y1,y2,-,yn},当Z={z1,z2-,zn}是X的严格递增下标顺序( ...

  6. 【动态规划】钢条切割问题

    本人在学习<算法导论>的过程中,对于动态规划这部分的内容不是特别理解,于是决定做一下学习与解决记录,欢迎讨论交流. 文章目录 0- 动态规划问题的一般步骤 1- 问题描述 2-问题分析 3 ...

  7. 动态规划:钢条切割问题

    一.题目 钢条切割问题 是<算法导论>一书中介绍动态规划时的一道引题.即: 某公司购买长钢条,将其切割为短钢条出售.假设切割工序没有成本支出,已知长度为 i 的钢条出售价格为 pi ,钢条 ...

  8. 数据结构(python) —— 【34: 动态规划之钢条切割问题】

    钢条切割问题 1. 问题 某公司出售钢条,出售价格与钢条长度之间的关系如下表: 问题:现有一段长度为n的钢条和上面的价格表,求切割钢条方案,使得总收益最大. 2. 思路 思考: 长度为n的钢条的不同切 ...

  9. 贪心、动态规划:钢条切割

    题目描述 Serling公司购买长钢条,将其切割为短钢条出售.切割工序本身没有成本支出.公司管理层希望知道最佳的切割方案. 假定我们知道Serling公司出售一段长为i英寸的钢条的价格为pi(i=1, ...

最新文章

  1. apache 2.4 配置php,Apache2.4 PHP 配置
  2. 字段缩写ti表示什么_【滴水研究】解码TI(一)
  3. (转)jQuery第五课:Ajax
  4. zen cart 操作-修改
  5. 添加icon_在zotero中添加百度学术、中国知网的文章检索引擎
  6. float去掉小数点之后_float类型的存储方式
  7. ITU-T Technical Paper: 测量QoS的基本网络模型
  8. 前端工程化(Vue-cli3和Element-ui)
  9. SQL Server 修改AlwaysOn共享网络位置
  10. java 局部内部类
  11. 2022最新软考考试时间已公布
  12. Win10在BIOS中如何启用虚拟化(VT)
  13. 【第二周】吴恩达团队AI for Medical Diagnosis课程笔记
  14. 读《天才在左 疯子在右》有感
  15. IDEA下,Ctrl+Alt+方向键,屏幕翻转问题
  16. uniapp H5 实现地图选址功能
  17. 尚融宝28-投资列表展示
  18. C++捕获全屏(截全屏)
  19. java-net-php-python-jspm人力外包服务公司招聘管理系统计算机毕业设计程序
  20. 基于带约束S型加减速曲线的空间直线插补与空间圆弧插补算法(Matlab)

热门文章

  1. 【观察】帆软:扎根于BI,收获于未来
  2. video读取服务器本地的视频文件,javascript-video.js无法读取本地视频
  3. 用 GreaseMonkey (油猴)解码 TinyURL
  4. 2019Python人工智能前景怎么样?
  5. android中流媒体
  6. 【正点原子MP157连载】第二十八章 A7和M4联合调试-摘自【正点原子】STM32MP1 M4裸机CubeIDE开发指南
  7. 【转载】我到底该不该继续交社保?
  8. 小程序页面如何直接调用云存储中的图片
  9. 重装战姬服务器正在维护,《重装战姬》4月23日更新维护公告
  10. win7设置计算机共享的打印机共享的打印机共享,告诉你win7打印机共享设置教程...