经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » 编程经验 » 查看文章
算法学习——动态规划之装载问题 - Stars-one
来源:cnblogs  作者:Stars-one  时间:2018/11/14 9:45:55  对本文有异议

算法描述

两艘船各自可装载重量为c1,c2,n个集装箱,各自的重量为w[n],设计一个可以装载的方案,使得两艘船装下全部集装箱

算法思路

  1. 将第一艘船尽量装满(第一艘船放的集装箱的重量之和接近c1),剩余的集装箱放入第二艘船,若剩余的集装箱重量之和大于第二艘船,则无解

  2. 定义一个一维数组,a[n] 存放对应的集装箱的重量

  3. 定义一个数组,m[i][j]表示第一艘船还可装载的重量j,可取集装箱编号范围为i,i+1...n的最大装载重量值

    例如 现在有3个集装箱 重量分别为9,5,3,即a[1]=9 a[2]=5 a[3]=3

    m[1][2]=0 可装载重量为2,此时上述的三个集装箱都不能装入,所以为最大可装载重量为0

    m[1][3]=m[1][4]=3 可装载重量为3或者是4的时候,都是只能装入重量为3的那个集装箱,所以最大可装载重量为3 `

    实际上,这里的3=a[3]+m[1][2],是一个递推的关系,具体看下面`

  4. m[i][j]分下面两种情况
    • 0<=j<a[n] (当可装载重量j小于第n个集装箱的重量w[n],此时就不能往船上装此集装箱) m[i][j] = m[i+1][j]

    • j>=a[n]可装载重量j大于或等于第n个集装箱的重量w[n]),此时剩余的可装载重量为j-a[n](装入了此时的集装箱),最大的可装载重量为m[i+1][j-w[n]]+w[n]

      但是我们是需要最大的可装载重量,所以得与如果不将当前集装箱装入的那种情况m[i+1][j]进行比较

      m[i][j]=Math.max(m[i+1][j],m[i+1][j-a[n]+a[n]])

  5. 上面我们就获得了一个关于m[i][j]的递推关系,我们通过逆推获得全部的数值

    • 初始值

      m[i][j]=0 这里的i=n j从0到a[n] 这里的a[n]是第n个集装箱重量(最后一个集装箱的重量)

      这里的赋值其实就是上述m[i][j]两种情况的第一种情况,最后一个集装箱的重量大于可装载重量,不装载此集装箱,所以最大可装载重量为0,

      m[i][j]=a[n] 这里的i=n j从a[n]到c1 这里的a[n]是第n个集装箱的重量(最后一个集装箱的重量)

      这里的意思为当可装载重量j只要都是大于最后一个集装箱的重量a[n],即可装入此集装箱,所以最大可装载重量等于装入的集装箱的重量

    • 开始逆推

      使用上述的递推公式进行逆推

      1. for (int i = n; i >= 1 ; i--) {
      2. for (int j = 1; j <=c1; j++) {
      3. if(j>=a[i]){
      4. m[i][j] = Math.max(m[i+1][j],m[i+1][j-a[i]]+a[i]);
      5. }else{
      6. m[i][j]=m[i+1][j];
      7. }
      8. }
      9. }
  6. 之后再进行输出,输出第一艘船的装载方案,输出第二艘船的装载方案

算法实现

  1. System.out.println("输入第一艘船可装载重量c1:");
  2. Scanner scanner = new Scanner(System.in);
  3. int c1 = scanner.nextInt();
  4. System.out.println("输入第二艘船可装载重量c2:");
  5. int c2 = scanner.nextInt();
  6. System.out.println("输入集装箱个数n:");
  7. int n = scanner.nextInt();
  8. int[] a = new int[n+1];
  9. //使用一维数组存放集装箱重量
  10. System.out.println("依次输入集装箱的重量");
  11. for (int i =1; i < n+1; i++) {
  12. a[i] = scanner.nextInt();
  13. }
  14. int sum = 0;//集装箱重量总和
  15. for (int i = 0; i < a.length; i++) {
  16. sum=sum+a[i];
  17. }
  18. //超重情况
  19. if(sum>c1+c2){
  20. System.out.println("集装箱重量之和大于两艘船可装载重量,题目无解");
  21. return;//结束程序
  22. }
  23. int[][] m = new int[100][100];//m[i][j]表示第一艘船还可装载的重量j,可取集装箱编号范围为i,i+1...n的最大装载重量值
  24. //赋初始值,由于是逆推,所以从末尾开始
  25. //可装载重量j小于第n个集装箱重量a[n],不装此集装箱,赋值为0
  26. for (int j = 0; j < a[n]; j++) {
  27. m[n][j] = 0;
  28. }
  29. //可装载重量j大于或等于第n个集装箱重量a[n],装载此集装箱,此时刻最大装载重量值为a[n]
  30. for (int j = a[n]; j <=c1 ; j++) {
  31. m[n][j]=a[n];
  32. }
  33. //关键逆推代码
  34. for (int i = n; i >= 1 ; i--) {
  35. for (int j = 1; j <=c1; j++) {
  36. if(j>=a[i]){
  37. m[i][j] = Math.max(m[i+1][j],m[i+1][j-a[i]]+a[i]);
  38. }else{
  39. m[i][j]=m[i+1][j];
  40. }
  41. }
  42. }
  43. int maxc1 = m[1][c1];//最大可装载重量
  44. System.out.println("maxc1="+maxc1);
  45. if(maxc1>sum-c2){
  46. int cw = m[1][maxc1];
  47. int sw,i;
  48. //输出第一艘船的装载
  49. System.out.println("第一艘船装载:");
  50. for (sw=0,i=1;i<=n;i++){
  51. if(m[i][cw]>m[i+1][cw]){
  52. cw = cw-a[i];
  53. sw=sw+a[i];//统计sw,sw的最终结果与maxc1相等
  54. System.out.print(a[i]+" ");
  55. a[i]=0;//装载当前的集装箱
  56. }
  57. }
  58. System.out.print("("+sw+")");
  59. System.out.println("");
  60. //输出第二艘船的装载
  61. System.out.println("第二艘船装载:");
  62. for(sw=0,i=1;i<=n;i++){
  63. //已装载在第一艘船的集装箱a[i]都已经为0了,只需要将不为0的那些集装箱装入第二艘船即可
  64. if(a[i]!=0){
  65. System.out.print(a[i]+" ");
  66. sw=a[i]+sw;
  67. }
  68. }
  69. System.out.println("("+sw+")");
  70. }else{
  71. System.out.println("无解");
  72. }

结果

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号