1. 程式人生 > >小飛的電梯排程演算法

小飛的電梯排程演算法

1、問題描述:

某大廈一共有6部電梯,在高峰時間,每層都有人上下,電梯在每層都停,實習生小飛常常會被每層都停的電梯弄的很不耐煩,於是他提出了這樣一個辦法:由於樓層不太高,每次電梯往上走時,我們只允許電梯停在其中的某一層。所有乘客都從一樓上電梯,到達某層後,電梯停下來,所有乘客再從這裡爬樓梯到自己的目的層。在一樓的時候,每個乘客選擇自己的目的層,電梯自動計算出相應的樓層。電梯應停在哪一層,能夠保證這次乘坐電梯的所有乘客爬樓梯的層數之和最小?

2、分析:

該問題本質上是一個優化問題,從問題中我們可以看到,影響結果的主要有兩個因素:乘客人數和電梯停的層數。假設樓層總共有N層,電梯停在x層,到第i層的乘客人數為Tot[i],則所爬樓梯的總數是:|x-1|*Tot[1]+|x-2|*

Tot[2]+.....+|x-N|*Tot[N]。我們就是尋找一個最優的x,使總和最小。

3、解法:

<1>解法一

可以從第一層開始來列舉x,一直到第N層,然後計算出乘客所爬樓梯的總數,並求出最小值以及此時的x的值。這個演算法的時間複雜度為O(n*n)。

#include <iostream>

using namespace std;

void min_floor(int floor_num,int tot_person[]);//參一:樓層總數;參二:去每層的人數

int main()
{
	int tot_person[7] = { 0,1, 2, 2, 0, 3, 2 };
	min_floor(6, tot_person);
}

void min_floor(int floor_num, int tot_person[])
{
	int i,j, minFloor,total_floor = 0, target_floor = -1;

	for (i = 1; i <= floor_num;i++)
	{
		for (j = 1; j <= i; j++)
			total_floor += tot_person[j] * (i - j);
		for (j = i + 1; j <= floor_num;j++)
			total_floor += tot_person[j] * (j - i);
		if (target_floor == -1 || minFloor > total_floor)
		{
			target_floor = i;
			minFloor = total_floor;
		}
		total_floor = 0;
	}
	cout << "目標樓層:" << target_floor << endl << "最少層數:" << minFloor << endl;
}
執行結果:

<2>解法二

假設電梯停在第i層樓,那我們可以計算出所有乘客爬的總樓層數Y。如果有N1個乘客目的樓層在i層樓以下,N2個乘客目的樓層在i層樓,N3個乘客在i層樓以上。在這種情況下,如果電梯改停在(i+1)層,那麼目的樓層在i層以上的乘客將少爬一層,即N3個乘客將少爬N3層,目的樓層在i層及i層以下的乘客將多爬一層,及多爬(N1+N2)層,因此所有乘客爬的樓層數為Y-N3+N1+N2 = Y+(N1+N2-N3)。同理可以求的電梯改停在(i-1)層時,乘客所爬的樓層總數為Y-(N1-N2-N3)。由此可見當N1+N2 < N3時乘客少爬的樓層數為N3-N1-N2,電梯在i+1層停更好;如果N2+N3 < N1,乘客少爬的樓層數為N1-N2-N3,電梯停在i-1層更好;其它情況停在i層更好。

根據這個規律我們從第一層開始考察,計算乘客所爬樓梯的總數。然後再根據上面的策略進行調整,直到找到最佳樓層。總的時間複雜度為O(N)。

#include <iostream>

using namespace std;
void min_floor_second(int floor_num, int tot_person[]);//參一:樓層總數;參二:去每層的人數

int main()
{
	int tot_person[7] = { 0,1, 2, 2, 0, 3, 2 };
	min_floor_second(6,tot_person);
}

void min_floor_second(int floor_num, int tot_person[])
{
	int N1 = 0, N2 = tot_person[1], N3 = 0;
	int i, target_floor = 1,min_floor = 0;

	for (i = 2; i <= floor_num; i++)
	{
		N3 += tot_person[i];
		min_floor += tot_person[i] * (i - 1);
	}

	for (i = 2; i <= floor_num;i++)
	{
		if ( (N1 + N2) < N3)
		{
			target_floor = i;
			min_floor += (N1 + N2 - N3);
			N3 -= tot_person[i];
			N1 += N2;
			N2 = tot_person[i];
		}
		else
			break;
	}
	cout << "目標樓層:" << target_floor << endl << "所爬層數:" << min_floor << endl;
}
執行結果: