[编程之美] PSet1.8 小飞的电梯调度算法

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

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

解法一:暴力枚举法。从第1层枚举到第N层,求出电梯在x层停的话,所有乘客需要怕多少层楼。求出最少的那层即可。O(N^2)

int findTargetFloor(int *Peoples , int N)
{
    int nFloors=0;
    int minFloors = -1;
    int targetFloor = 0;
    for(int i=1 ; i<=N ; i++){
        for(int j=1 ; j<i ; j++)
            nFloors+=Peoples[j]*(i-j);
        for(int j=i+1 ; j<=N ; j++)
            nFloors+=Peoples[j]*(j-i);
        if(nFloors < minFloors || minFloors == -1){
            minFloors = nFloors;
            targetFloor = j;
        }
    }
    return targetFloor;
}

解法二:书上提供的O(N)的动态规划的算法。

假设电梯停在i层楼,可以计算出所有乘客要爬楼层的层数为Y,假设此时有N1个乘客在i层楼以下,N2个乘客在I层楼,N3个乘客在I层楼以上,则当电梯停在i+1层的时候,N1+N2个乘客要多下一层楼,共多下N1+N2层,N3个乘客要少往上面爬一层楼,少上N3层楼,此时Y(i+1) = Y(i) + N1+N2-N3,很显然,当N1+N2<N3的时候,Y不断减小。Y1很容易算出来,另外我们还可以看出,N1+N2是递增的,N3是递减的,所以N1+N2一旦大于N3的时候,我们直接退出循环即可,没有必要再计算下去了。

int findKFloor(int *Peoples , int N)
{
    int targetFloor = -1;

    int minFloors = 0;
    int N1=0 ;
    int N2=Peoples[1];
    int N3=0 ;
    for(int i=2 ; i<=N ; i++){
        N3 +=Peoples[i];
        minFloors += Peoples[i]*(i-1);
    }
    
    for(int i=2; i<=N ; i++){
        if(N1+N2<N3){
            minFloors += N1+N2-N3;
            targetFloor = i;
            N1 = N1+N2;
            N2 = Peoples[i];
            N3 = N3-Peoples[i];
        }
        else
            break;
    }
    return targetFloor;
}

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

//向上爬一层需要UPCOST能量
//向下爬一层需要1单位能量
//总共有N层楼(下标从1开始)
int findKFloor(int *Peoples , int N)
{
    int targetFloor = -1;
    int N1 = 0;
    int N2 = Peoples[1];
    int N3 = 0;
    int minFloors = 0;//最低能量
    for(int i=2 ; i<=N ; i++){
        N3 += Peoples[i];//在第一层以上的人数之和
        minFloors += Peoples[i]*(i-1)*UPCOST;//最低能量代价
    }
    for(int i=2 ; i<=N ; i++){
        if(N1+N2 < N3*UPCOST){
            targetFloor = i;
            minFloors += N1+N2-N3*UPCOST;
            N1 = N1+N2;
            N2 = Peoples[i];
            N3 = N3-Peoples[i];
        }
        else 
            break;
    }
    return targetFloor;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值