電梯調度算法
題目描述
大廈中有電梯,在高峰時間,每層都有人上下,電梯在每層都停。
想的解決辦法如下:
所有的乘客都從一樓上電梯,每個乘客選擇自己的目的層,之后電梯自動計算出一個樓層。
電梯往上走時,只在這個樓層停下來,所有的乘客再從這里爬樓梯到自己的目的樓層。
現在就想問,電梯停在哪一層樓,能夠保證這次乘坐電梯的所有乘客爬樓梯的層數之和最少。
分析
該問題本質上是一個優化問題。
首先為這個問題找到一個合適的抽象模型。
有兩個因素會影響結果:乘客的數目和乘客的目的樓層。
假設樓層總共有N層,電梯停在x層,要去第i層的乘客數目總數為Tot[i],這樣,所爬樓梯的總數就是:
因此,我們就是需要找到一個整數x,使得上式的值最小。
解法一
最為直接的一個解法就是從第一層開始,枚舉x一直到第N層,計算出電梯在第x層樓停的話,所有乘客總共需要爬多少樓。
這個算法需要兩重循環來完成。
代碼如下:

#include <iostream> using namespace std; int main(int argc, char* argv[]) { int N = 0; int nPerson[100]; int nFloor, nMinFloor, nTargetFloor; nTargetFloor = -1; while( cin >> N) //輸入總的樓層 { //進行狀態清零 nTargetFloor = -1; nMinFloor = 0; //輸入到每一層的人的個數 for(int i = 0; i < N; ++i) { cin >> nPerson[i]; } //開始計算最佳樓層 for(int i = 0; i < N; ++i) { //對於每一個樓層,先假設是停在這個樓層 //用一個變量記錄要步行的樓層總數 nFloor = 0; //假設停在第i層,統計所有人需要步行的樓層總數 for(int j = 0; j < N; ++j) { if(j < i) { nFloor += nPerson[j] * (i - j); } else if(j > i) { nFloor += nPerson[j] + (j - i); } } //第一次記錄,或者當前結果小於之前最小時,記錄結果 if(-1 == nTargetFloor || nMinFloor > nFloor) { nMinFloor = nFloor; nTargetFloor = i; } } //輸出計算結果 cout << "The best floor is: " << nTargetFloor + 1 << endl; } return 0; }
這個基本解法的時間復雜度為O(N2)。
解法二
假設電梯停在i層,我們可以計算出所有乘客總共需要爬樓梯的層數Y。
假設有N1個乘客在i層樓以下,N2個乘客在第i層樓,還有N3個乘客在第i層樓以上。
這個時候,如果電梯改停在i-1層,所有目的地在第i層及以上的乘客都需要多爬一層,即N2+N3層,而所有目的地在i-1層及以下的乘客可以少爬一層,總共可以少爬N1層。
因此,乘客總共需要爬的層數為Y-N1+N2+N3 = Y-(N1-N2-N3)層。
反之,如果電梯在i+1層停,則總共需要爬的層數為Y+(N1+N2-N3)層。
由此可見:
當N1 > N2 + N3時,i-1層比i層好;
當N1 + N2 < N3時,i+1層比i層好。
根據這個規律,我們從第一層開始考察,計算各位乘客需要爬樓梯的層數。然后再根據上面的策略進行調整,直到找到最佳樓層。

#include <iostream> using namespace std; int main(int argc, char* argv[]) { int N = 0; int nPerson[100]; int nMinFloor, nTargetFloor; int N1, N2, N3; while( cin >> N) //輸入總的樓層 { //輸入到每一層的人的個數 for(int i = 0; i < N; ++i) { cin >> nPerson[i]; } //進行狀態清零 nTargetFloor = 0; nMinFloor = 0; N1 = 0; N2 = nPerson[0]; N3 = 0; for (int i = 1; i < N; ++i) { N3 += nPerson[i]; nMinFloor += nPerson[i] * (i - 1); } for(int i = 1; i < N; ++i) { if(N1 + N2 < N3) { nTargetFloor = i; nMinFloor +=(N1 + N2 - N3); N1 += N2; N2 = nPerson[i]; N3 -= N2; } else { //否則第i層的結果已經最小,故不需要計算第i+1層 break; } } //輸出計算結果 cout << "The best floor is: " << nTargetFloor + 1 << endl; } return 0; }
總的時間復雜度將降為O(N)。
參考資料
《編程之美》1.8節
相關博客:http://www.cppblog.com/jake1036/archive/2011/06/29/149720.html?opt=admin
PS:
每天更新有點扛不住了,還是不要強求每天了。。。