• 第1章 游戏之乐——小飞的电梯调度算法


    小飞的电梯调度算法

    1. 问题描述:

    亚洲微软研究院所在的希格玛大厦一共有6部电梯。在高峰时间,每层都有人上下,电梯每层都停。实习生小飞常常会被每层都停的电梯弄的很不耐烦,于是他提出了这样一个办法:
    由于楼层并不算太高,那么在繁忙的上下班时间,每次电梯从一层往上走时,我们只允许电梯停在其中的某一层。所有乘客从一楼上电梯,到达某层后,电梯停下来,所有乘客再从这里爬楼梯到自己的目的层。在一楼的时候,每个乘客选择自己的目的层,电梯则计算出应停的楼层。

    问:电梯停在哪一层楼,能够保证这次乘坐电梯的所有乘客爬楼梯的层数之和最少?

    2. 【解法一】暴力求解(枚举法)时间复杂度O(N2)

     1 package chapter1youxizhileElevatorScheduling;
     2 /**
     3  * 小飞的电梯调度算法
     4  * 【解法一】枚举法
     5  * @author DELL
     6  *
     7  */
     8 public class ElevatorScheduling1 {
     9     private int nPerson[];  //nPerson[i]表示到第i层的乘客数目
    10     private int nFloor;  //电梯的总层数
    11     //构造函数
    12     public ElevatorScheduling1(int[] nPerson, int nFloor){
    13         this.nPerson = nPerson;
    14         this.nFloor = nFloor;
    15     }
    16     
    17     public int getTargetFloor(){
    18         int minFloor = 30*nFloor; //记录爬楼梯总和的最小值,初始时设为一个较大的值
    19         int targetFloor = -1;  //电梯停的目标层,初始为-1
    20         for(int i=1;i<=nFloor;i++){  //逐个试探i值
    21             int sum = 0;  //记录爬楼梯的总数和
    22             for(int j=0;j<nFloor;j++){  //实际的层数为j+1
    23                 sum += nPerson[j]*Math.abs(j+1-i);
    24             }
    25             if(targetFloor==-1||minFloor>sum){
    26                 minFloor = sum;
    27                 targetFloor = i;
    28             }
    29         }
    30         System.out.println("爬楼梯层数的最小值为:"+minFloor);
    31         return targetFloor;
    32     }
    33     public static void main(String[] args) {
    34         int nPerson[] = {0,1,3,3,4,6,8,4};
    35         ElevatorScheduling1 es = new ElevatorScheduling1(nPerson, 8);
    36         System.out.println("电梯的目标层应为:"+es.getTargetFloor());
    37 
    38     }
    39 
    40 }

    程序运行结果如下:

    爬楼梯层数的最小值为:39
    电梯的目标层应为:6

    3.【解法二】动态规划(时间复杂度为O(N))

     1 package chapter1youxizhileElevatorScheduling;
     2 /**
     3  * 小飞的电梯调度算法
     4  * 【解法二】动态规划
     5  * @author DELL
     6  *
     7  */
     8 public class ElevatorScheduling2 {
     9     private int nPerson[];  //nPerson[i]表示到第i层的乘客数目
    10     private int nFloor;  //电梯的总层数
    11     //构造函数
    12     public ElevatorScheduling2(int[] nPerson, int nFloor){
    13         this.nPerson = nPerson;
    14         this.nFloor = nFloor;
    15     }
    16     
    17     /**
    18      * 计算目标层
    19      * @return 目标层
    20      */
    21     public int getTargetFloor(){
    22         int minFloor = 0; //记录爬楼梯总和的最小值
    23         int targetFloor = -1;  //电梯停的目标层,初始为-1
    24         int i;
    25         int N1; //第i层以下的乘客数目
    26         int N2; //第i层的乘客数目
    27         int N3; //第i层以上的乘客数目
    28         //计算第一层的N1,N2,N3值
    29         N1 = 0;
    30         N2 = nPerson[0];
    31         for(N3=0,i=1;i<nFloor;i++){
    32             N3 += nPerson[i];
    33             minFloor += nPerson[i]*i;
    34         }
    35         //判断是否需要改变i值
    36         for(i=2;i<=nFloor;i++){
    37             if(N1+N2<N3){
    38                 targetFloor = i;
    39                 minFloor += N1+N2-N3;
    40                 N1 += N2;;
    41                 N2 = nPerson[i-1];
    42                 N3 -= nPerson[i-1];
    43             }else{
    44                 break;
    45             }
    46         }
    47         System.out.println("爬楼梯层数的最小值为:"+minFloor);
    48         return targetFloor;
    49     }
    50     public static void main(String[] args) {
    51         int nPerson[] = {0,1,3,3,4,6,8,4};
    52         ElevatorScheduling2 es = new ElevatorScheduling2(nPerson, 8);
    53         System.out.println("电梯的目标层应为:"+es.getTargetFloor());
    54     }
    55 
    56 }

    程序运行结果如下:

    爬楼梯层数的最小值为:39
    电梯的目标层应为:6

     扩展问题:

      往上爬楼梯,总是比往下走要累的。假设往上爬一个楼层,要耗费k单位的能量,而往下走只需要耗费1单位的能量,那么如果题目条件改为让所有人消耗的能量最少,这个问题怎么解决呢?

     【解法一】暴力求解(枚举法)时间复杂度O(N2)

    只需将上述【解法一】中的

    22             for(int j=0;j<nFloor;j++){  //实际的层数为j+1
    23                 sum += nPerson[j]*Math.abs(j+1-i);
    24             }

    改为:

                int j;
                for(j=0;j<i-1;j++){
                    sum += nPerson[j]*(i-j-1)*k;
                }
                for(j=i;j<nFloor;j++){
                    sum += nPerson[j]*(j+1-i)*1;
                }

      【解法二】动态规划(时间复杂度为O(N))

    只需将上述【解法二】中的

    31         for(N3=0,i=1;i<nFloor;i++){
    32             N3 += nPerson[i];
    33             minFloor += nPerson[i]*i;
    34         }
    35         //判断是否需要改变i值
    36         for(i=2;i<=nFloor;i++){
    37             if(N1+N2<N3){
    38                 targetFloor = i;
    39                 minFloor += N1+N2-N3;
    40                 N1 += N2;;
    41                 N2 = nPerson[i-1];
    42                 N3 -= nPerson[i-1];
    43             }else{
    44                 break;
    45             }
    46         }

    改为:

            for(N3=0,i=1;i<nFloor;i++){
                N3 += nPerson[i];
                minFloor += nPerson[i]*i*1;
            }
            //判断是否需要改变i值
            for(i=2;i<=nFloor;i++){
                if((N1+N2)*k<N3){
                    targetFloor = i;
                    minFloor += (N1+N2)*k-N3;
                    N1 += N2;;
                    N2 = nPerson[i-1];
                    N3 -= nPerson[i-1];
                }else{
                    break;
                }
            }
  • 相关阅读:
    android:versionCode和android:versionName 用途
    ProgressDialog使用总结
    对 Android 开发者有益的 40 条优化建议
    Android TextView换行问题
    Android TextView自动换行文字排版参差不齐的原因
    Python 生成requirement 使用requirements.txt
    PLSQL简介
    python魔法方法详解
    深入了解Token认证的来龙去脉
    数组、链表、栈、队列和STL
  • 原文地址:https://www.cnblogs.com/gaopeng527/p/4605604.html
Copyright © 2020-2023  润新知