编程之美 1.8小飞的电梯调度算法
题目:
亚洲微软研究院所在的希格玛大厦一共有6部电梯。在高峰时间,每层都有人上下,电梯每层都停。实习生小飞常常会被每层都停的电梯弄的很不耐烦,于是他提出了这样一个办法:
由于楼层并不算太高,那么在繁忙的上下班时间,每次电梯从一层往上走时,我们只允许电梯停在其中的某一层。所有乘客从一楼上电梯,到达某层后,电梯停下来,所有乘客再从这里爬楼梯到自己的目的层。在一楼的时候,每个乘客选择自己的目的层,电梯则计算出应停的楼层。
问:电梯停在哪一层楼,能够保证这次乘坐电梯的所有乘客爬楼梯的层数之和最少?
方法一:暴力枚举,时间复杂度O(N^2)
用数组nPerson[i]存放在第i层下楼的人数,在不同的i层停靠,求所有人需要走的楼层总和,找出总和最小的楼层Target,输出。用两重循环完成计算。
1 /* 2 * 1.8.1 3 * 4 * Created on: Jan 9, 2016 5 * Author: SeekHit 6 */ 7 #include "iostream" 8 #define N 100 9 10 using namespace std; 11 12 int func(int n, int nPerson[]){ 13 14 int nFloor, nMinFloor=0, TargetFloor=0; 15 16 for (int i = 1; i <= n; i++){ 17 nFloor = 0; 18 for (int j = 1; j<i; j++) 19 nFloor += (i - j)*nPerson[j]; 20 for (int j = i + 1; j <= n; j++) 21 nFloor += (j - i)*nPerson[j]; 22 23 if (TargetFloor==0||nMinFloor>nFloor){ //如果没有TargetFloor==0,nMinFloor>nFloor始终无法满足,不执行if里面的内容 24 nMinFloor = nFloor; 25 TargetFloor = i; 26 27 } 28 } 29 return TargetFloor; 30 } 31 32 int main(){ 33 int n, Target; 34 int nPerson[N]; 35 cout<<"输入楼层总数n:"<<endl; 36 cin>>n; 37 cout<<"输入每层楼下的人数"<<endl; 38 for (int i = 1; i <= n; i++){ 39 cout<<"第"<<i<<"层下的人数:"<<endl; 40 cin>>nPerson[i]; 41 } 42 43 Target = func(n, nPerson); 44 cout<<"电梯停靠最优层数为:"<<Target<<endl; 45 }
方法二:时间复杂度为O(N)的动态规划的算法
降低时间复杂度,求解。假设停在i层,可以计算出所有乘客需要爬的楼层总数Y。设N1个人在i层以下下楼,N2个人在i层下楼,N3个人在i层以上下楼。
如果现在电梯改在i-1层停靠,现在所有i层和i层以上的都要多走一楼,相当于,总共多爬了N2+N3层,而i层以下的所有人少爬了一楼,就是少了N1层。总数变成了N2+N3-N1层,如果N2+N3-N1<Y,说明降一层停靠更优。
反之,如果i+1层停靠,所有乘客爬的楼层数变成了N1+N2-N3,如果N1+N2-N3<Y说明升一层停靠更优。
书上给的程序就是用升楼的方式来判断的,也可以用降楼来动态规划最优楼层数。
1 /* 2 * 1.8.2动态规划 3 * 4 * Created on: Jan 9, 2016 5 * Author: SeekHit 6 */ 7 #include "iostream" 8 #define N 100 9 10 using namespace std; 11 12 int func(int n, int nPerson[]){ 13 14 int nMinFloor=0, TargetFloor=1; 15 int N1=0,N2=nPerson[1],N3=0; 16 17 //计算N3,就停靠在1楼时,需要走的总楼层数 18 for (int i = 2; i <= n; i++){ 19 N3+=nPerson[i]; 20 nMinFloor+=nPerson[i]*(i-1); 21 } 22 23 for(int i=2;i<=n;i++){ 24 if(N1+N2<N3){ 25 TargetFloor=i; 26 nMinFloor+=(N1+N2-N3); 27 N1+=N2; 28 N2+=nPerson[i]; 29 N3-=nPerson[i]; 30 } 31 else 32 break; 33 } 34 return TargetFloor; 35 } 36 37 int main(){ 38 int n, Target; 39 int nPerson[N]; 40 cout<<"输入楼层总数n:"<<endl; 41 cin>>n; 42 cout<<"输入每层楼下的人数"<<endl; 43 for (int i = 1; i <= n; i++){ 44 cout<<"第"<<i<<"层下的人数:"<<endl; 45 cin>>nPerson[i]; 46 } 47 48 Target = func(n, nPerson); 49 cout<<"电梯停靠最优层数为:"<<Target<<endl; 50 }
运行结果:
扩展问题:
往上爬比往下走要累,往上爬一层消耗k个单位的能量,往下走只消耗1个单位的能量,求让所有人消耗的能量最少。
解法:
只需将计算N1+N2-N3变成N1+N2-N3*K即可。其余的都一样。