title: 算法设计与分析实验二:钢条切割问题
date: 2021-05-19

钢条切割问题

1.问题描述
设有一个长度为 L 的钢条,在钢条上标有 n 个位置点(p1,p2,…,pn)。现在需要按钢条上标注的位置将钢条切割为 n+1 段,假定每次切割所需要的花费与所切割的钢条长度成正比。请编写⼀个算法,能够确定⼀个切割方案,使切割的总花费最小。
数据规模:
⚫ 2 ≤ L ≤ 105
⚫ 1 ≤ n ≤ 200
⚫ 1 ≤ 𝑝𝑖 < 𝐿
2.题目分析
用数组表示一钢条。0、1、2、…、len为坐标,设x_i为一切割点且位于坐标i处。切断x_i后,钢条分为左右两段子钢条,原钢条是最大的子钢条。现设钢条的左右端点为x_0,x_len,对于中间钢条,切掉一次后也变成了端点钢条。则左右两子钢条可以记作(x_0,x_i),( x_i,x_len)。按照这种记法,原钢条可以记为(x_0,x_len)。

要切下一段钢条需要一次或两次切割:切掉端点处的钢条需要一次;切掉中间的钢条需要两次。现按照三元组的记法来确定一段切割:记三元组M_mn=(x_m,x_i,x_n)为切割mn,0<m<i<n<len。其中x_i为切割点,则一个三元组中有正整数个切割点。以二元数组(矩阵)的形式建立备忘录记录任意三元组最小总花费。

总花费是指将该三元组切割到不可再分的所有花费。由于给定三元组的端点就确定了本次切割花费,故定义总花费的概念。钢条的花费与长度成正比,则不妨取二者相等。由此有某一三元组M_mn的总花费
算法设计与实验二:钢条切割 - 图1

由此递推式可以求出元钢条的最小花费。
3.程序设计
现设计程序:
设钢条长度为barlen。经实际编程后发现对于钢条只需要知道长度。
可用一数组x存储切割点。设切割点共有xnum个,则x长度应为xnum+2(两端视为切割点)。
输入后动态生成两数组,先初始化再逐渐优化。
值得注意的是:
输入的xnum要加2,因为把端点也看做切割点。
memo只需要存储切割点即可,而不需存储其他点。
lowestCost函数中应采用步长而不是循环每一行每一列。这是因为大步长的结果需要用到小步长的结果。
4.代码
代码如下:

  1. #include"iostream"
  2. #include"algorithm"
  3. #define INF 100000000
  4. using namespace std;
  5. int num; int barlenn;
  6. int main()
  7. {
  8. int lowestCost(int m, int n, int* &x, int xlen, int** &memo);
  9. int* x;//切割点数组
  10. int** memo;//备忘录矩阵
  11. int barnum, xnum;
  12. cin >> barnum >> xnum;
  13. int xlen = xnum + 2;
  14. num = xlen;
  15. int barlen = barnum + 1;//应有长度
  16. x = new int[xlen];
  17. x[0] = 0; x[xlen - 1] = barnum;
  18. for (int i = 1; i < xlen - 1; i++)
  19. {
  20. cin >> x[i];
  21. }
  22. //切割点排序
  23. sort(x, x + xlen);//注意排序函数用法
  24. //初始化备忘录
  25. memo = new int*[xlen];
  26. for (int i = 0; i < xlen; i++)
  27. memo[i] = new int[xlen];
  28. for (int i = 0; i < xlen; i++)
  29. {
  30. for (int j = 0; j < xlen; j++)
  31. memo[i][j] = INF;
  32. }
  33. int result;
  34. result = lowestCost(0, xlen - 1, x, xlen, memo);
  35. cout << result << endl;
  36. //释放指针数组
  37. if (x)
  38. delete[] x;
  39. if (memo)
  40. {
  41. for (int i = 0; i < xnum; i++)
  42. {
  43. if (memo[i])
  44. delete[] memo[i];
  45. }
  46. delete[] memo;
  47. }
  48. return 0;
  49. }
  50. int lowestCost(int m, int n, int* &x, int xlen, int** &memo)
  51. {
  52. for (int i = 0; i < xlen; i++)
  53. {
  54. memo[i][i] = 0;
  55. if (i + 1 < xlen)
  56. {
  57. memo[i][i+1] = 0;
  58. }
  59. if (i + 2 < xlen)
  60. {
  61. memo[i][i+2] = x[i + 2] - x[i];
  62. }
  63. }
  64. int temp;
  65. //应采用步长
  66. for (int step = 3; step <= x[xlen - 1]; step++)//注意边界
  67. {
  68. for (int m = 0; m < xlen; m++)
  69. {
  70. if (m + step <= xlen - 1)
  71. {
  72. for (int i = m + 1; i < m + step; i++)
  73. {
  74. temp = memo[m][i] + memo[i][m + step] + x[m + step] - x[m];
  75. if (temp < memo[m][m + step])
  76. {
  77. memo[m][m + step] = temp;
  78. }
  79. }
  80. }
  81. }
  82. }
  83. return memo[m][n];
  84. }

5.运行结果

算法设计与实验二:钢条切割 - 图2
算法设计与实验二:钢条切割 - 图3
算法设计与实验二:钢条切割 - 图4
算法设计与实验二:钢条切割 - 图5
算法设计与实验二:钢条切割 - 图6
附:输入文件
链接:https://pan.baidu.com/s/1Ii5jg1b36Zy76xFbox-7pw
提取码:umao