编程之美:第一章 1.8电梯调度算法

来源:互联网 发布:java 字符串随机排列 编辑:程序博客网 时间:2024/06/05 20:12
/*电梯调度算法:微软有6部电梯,每层都有人上下,电梯在每层都停。每次电梯从一层往上走时,只允许电梯停在其中的某一层。所有的乘客都从一楼上电梯,到达某层后,电梯停下来,所有乘客再从这里爬楼梯到自己的目的层。在一楼的时候,每个乘客选择自己的目的层,电梯则自动计算出应停在的楼层。电梯停在那一层,能够保证这次乘坐电梯的所有乘客爬楼梯的层数之和最少。分析:本质是优化问题。如何寻找抽象模型。树?图?影响结果的两个因素:乘客数目及需要停的目的楼层。我们可以从统计到达各层的乘客数目分析;假设楼层一共有N层,电梯停在第x层,要去第i层的乘客数目总数为Tot[i],这样所爬楼梯的总数就是从1到N 对Tot[i]*|i-x|求和我们只需要找到x即可解法1:可以从第一层开始枚举x一直到N层,计算出总共要爬的层数,然后选取最小值。每层楼计算时,要把所有N层楼计算一遍,时间复杂度为O(n),总共计算N层楼,因此总时间复杂度为O(n^2)解法2:假设电梯停在第i层楼,可以计算出所有乘客总共要爬楼梯的层数Y,如果有N1个乘客的目的楼层在i层楼一下,有N2个乘客在第i层楼,还有N3个乘客再第i层楼以上。这个时候,如果电梯改停在第i-1层,所有目的地在第i-1层及以下的乘客可以少爬一层,总共可以少爬N1层,而目的地在第i层及以上的乘客需要多爬一层,总共多爬N2+N3层乘客总共需要爬的层数为Y-N1+(N2 + N3) = Y - (N1 - N2 - N3)反之,如果电梯在i+1层停,乘客需要爬的层数为Y+N1+N2-N3停i-1:Y - N1 + N2 + N3,当N1 > N2 + N3时,停在第i-1层好,乘客少走N1-N2-N3停i+1:Y - N3 + N1 + N2,当N1 + N2 < N3时,停在第i+1层好,其他情况:停在第i层好我们从第一层开始考察,计算各位乘客需要爬的数目,然后调整,时间复杂度降为O(N) 输入:5(电梯层数,接下来有n行,第i行的数字表示第i层有多少人想停在这一楼,电梯标号默认从1开始,如果有多层相同,就输入标号最小的)3 5 8 9 44 20 2 3 4410 2 8 4输出:(第几层电梯,以及需要怕露底的数目)3 281 202 26分析:第一层停的话,那么第二层的人要走的层数:5,第三层:2*8,四:3*9,五:4*4 ,一共 = 5 + 16 + 27 + 16 = 64第二层停:一:3,三:8,四:2*9,五:3*4 =,共 = 3 + 8 + 18 + 12 = 41第三层停:一:2*3,二:5,四:9,五:2*4,一共 = 6 + 5 + 9 + 8 = 28第四层停:共= 3*3 + 2 *5 + 1*8 + 4*1 = 9 + 10 + 8 + 4 = 31第五层停:共= 4*3 + 3*5 + 2*8 + 1*9 = 12 + 15 + 16 + 9 = 52*//*关键:1 假设电梯停在第i层楼,可以计算出所有乘客总共要爬楼梯的层数Y,如果有N1个乘客的目的楼层在i层楼一下,有N2个乘客在第i层楼,还有N3个乘客再第i层楼以上。这个时候,如果电梯改停在第i-1层,所有目的地在第i-1层及以下的乘客可以少爬一层,总共可以少爬N1层,而目的地在第i层及以上的乘客需要多爬一层,总共多爬N2+N3层乘客总共需要爬的层数为Y-N1+(N2 + N3) = Y - (N1 - N2 - N3)反之,如果电梯在i+1层停,乘客需要爬的层数为Y+N1+N2-N3停i-1:Y - N1 + N2 + N3,当N1 > N2 + N3时,停在第i-1层好,乘客少走N1-N2-N3停i+1:Y - N3 + N1 + N2,当N1 + N2 < N3时,停在第i+1层好,其他情况:停在第i层好我们从第一层开始考察,计算各位乘客需要爬的数目,然后调整,时间复杂度降为O(N)2  for(i = 2,n1 = 0 ,n2 = pArr[1] , n3 = 0; i <= iLen ; i++)  //用第一层开始对第1层下面,第一层,第一层上面的人数赋值 {  n3 += pArr[i];  iMin += pArr[i]*(i-1); }3 //需要向上一层楼梯遍历的情况是:第i-1层和第i层都需要加走的步数需要累加:N1+N2,而第i层以上  //减少步数为:N3,如果N3> N1 + N2,此时应向上走  if(n3 > n1 + n2)  {   iMin -= (n3 - n1 - n2);   n1 += n2;   n3 -= pArr[i];//这里必须减去当前层数*/#include <stdio.h>#include <iostream>using namespace std;const int INT = 0x7fffffff;const int MAXSIZE = 10000;int abs(int n){ return n > 0 ? n : -1*n; }pair<int,int> elevatorAssign(int* pArr,int iLen){ int iMin = INT; int iMinIndex = -1; int iSum; for(int i = 1 ; i <= iLen ; i++) {  iSum = 0;  for(int j = 1 ; j <= iLen ; j++)  {   iSum += pArr[j]*abs(i - j);  }  if(iSum < iMin)  {   iMin = iSum;   iMinIndex = i;  } } return make_pair<int,int>(iMinIndex,iMin);}pair<int,int> elevatorAssign_optimized(int* pArr,int iLen){ int n1,n2,n3,i; int iMin = 0; for(i = 2,n1 = 0 ,n2 = pArr[1] , n3 = 0; i <= iLen ; i++)  //用第一层开始对第1层下面,第一层,第一层上面的人数赋值 {  n3 += pArr[i];  iMin += pArr[i]*(i-1); } for(i = 2 ; i <= iLen ; i++) {  //需要向上一层楼梯遍历的情况是:第i-1层和第i层都需要加走的步数需要累加:N1+N2,而第i层以上  //减少步数为:N3,如果N3> N1 + N2,此时应向上走  if(n3 > n1 + n2)  {   iMin -= (n3 - n1 - n2);   n1 += n2;   n3 -= pArr[i];//这里必须减去当前层数   n2 = pArr[i];  }  else  {   break;  } } return make_pair<int,int>(i-1,iMin);}void process(){ int n; while(EOF != scanf("%d",&n)) {  if(n <= 0)  {   break;  }  int iArr[MAXSIZE];  for(int i = 1 ; i <= n ; i++)  {   scanf("%d",&iArr[i]);  }  //pair<int,int> pairRes = elevatorAssign(iArr,n);  pair<int,int> pairRes = elevatorAssign_optimized(iArr,n);  printf("%d %d\n",pairRes.first,pairRes.second); }}int main(int argc,char* argv[]){ process(); getchar(); return 0;}


 

0 0