有一座大厦有很多工作租用,但是只有一部电梯,每天有很多人使用电梯。为了使电梯使用效率尽可能高,需要输入电梯中乘客想要到达的楼层,算法可以计算出电梯停靠的楼层使得效率最高。效率高地是由最后一个乘客到达想要到达的楼层的时间来衡量的。步行上一层楼需要20s,电梯上一层需要4s,停靠一层需要10s。算法输入为乘客想要停靠的楼层,输出为电梯计划停靠的楼层使得效率最高,即最后一个到达楼层的乘客时间最短。
因为停靠的组合较多,可以考虑搜索时间。所需时间的范围是可以确定的,最短时间为0,最长时间为把所有层次都停靠一遍的时间。在这个范围内枚举时间依次考察这个特定时间内电梯是否可以让最后一个到达的乘客到达。枚举比较慢,可以采用二分法枚举。
假设现在考察时间t,需要计算电梯应该停靠的楼层,对于在t时间内可以通过步行到达他们楼层的乘客就让他们步行即可。在t时间内步行可以到达的最高楼层为 t/20+1 (楼层从1开始计数)。也就是可以不考虑需要电梯停靠 t/20+1及其以下的乘客。
从t/20+2层开始搜索乘客需要停靠的楼层,如果有乘客需要在第i层停靠,那么电梯最好应该停在哪一层才能使得想要去i层的乘客在t时间内到达i层呢?自然是停的楼层越高越好,假设停靠的楼层为j,那么有临界方程 10*n + (j-1) * 4 + (j-i)*20 = t,其中n为之前已经停得次数,解得j=(t-10*n+20*i+4)/24。
在电梯停在j层之时,有部分乘客可以下电梯步行到j之上的楼层,并且会在t时间内到达,这部分楼层不必考虑,设j之上的最高楼层为i,这时有临界方程(i-j)*20+10*n+(j-1)*4 = t,解得i=(t-10*num+16*j+4)/20,下回就从i=(t-10*num+16*j+4)/20+1开始考虑乘客需要停靠的楼层即可。
#include <stdio.h>
#include <string.h>
const int M=30001;
bool ind[M];
int n;
int solve(int t){ // 判定时间 t 之内所有人是否都能到达目标层
int i,j,now=0,num=0;
i=t/20+2; // i 层一下的人直接走楼梯,哈哈
while(i<=n){
while(i<=n && ind[i]==false){ // i 层没人时不用理
i++;
}
if((i-1)*4+10*num>t)
return 0; // 电梯无法在时间 t 之内到达 i 层
j=(t-10*num+20*i+4)/24; // 电梯在第 j 层停靠最好
i=(t-10*num+16*j+4)/20+1; // 电梯 i 层以下的都已经搞定
num++;
}
return 1;
}
int main(){
int i,j,min,max,mid,t;
// freopen("data.txt","r",stdin);
while(1){
scanf("%d",&t);
if(t==0) break;
memset(ind,false,sizeof(ind));
n=-1; // 读入数据
for(i=0;i<t;i++){
scanf("%d",&j);
if(j>n) n=j;
ind[j]=true;
}
// 二分法,查找区间为 [min,max],其中min总是不可行的,max则为可行解
min=0;max=14*(n-1);
while(min<max-1){
mid=(min+max)/2;
if(solve(mid)==1) max=mid;
else min=mid;
}
printf("%d/n",max);
}
return 0;
}