问题: 电梯在高峰时为了提高效率,当人们进入电梯选择好楼层后,根据算法只停在其中的一层。这个算法要求电梯里所有的人爬楼梯的总数最少。
想法 I:算是穷举法吧,把每个人可能会爬的楼层数都计算出来,然后逐一求和后,再找出和最小的值。
假设有10层楼,5个人分别到3,6,9,10,5 层,穷举一下可以得到
2 5 8 9 4 = 28
停在第 1 层爬楼的总数
1 4 7 8 3 = 23
停在第 2 层爬楼的总数
0 3 6 7 2 = 18
停在第 3 层爬楼的总数
1 2 5 6 1 = 15
停在第 4 层爬楼的总数
2 1 4 5 0 = 12
停在第 5 层爬楼的总数
3 0 3 4 1 = 11
停在第 6 层爬楼的总数
4 1 2 3 2 = 12
停在第 7 层爬楼的总数
5 2 1 2 3 = 13
停在第 8 层爬楼的总数
6 3 0 1 4 = 14
停在第 9 层爬楼的总数
7 4 1 0 5 = 17 停在第 10 层爬楼的总数
这里可以看出:到第6层停是可以满足要求的。
代码:测试 假设一共有5个人分别去 3,6,9,10和5层
#include <iostream>
using namespace std;
#define PEOPLE 5
#define FLOORS 10
#define MAX 50
int arrTarget[PEOPLE] = {3,6,9,10,5};
int arrResult[FLOORS][PEOPLE];
int arrClmib[FLOORS];
void print(int arr[FLOORS][PEOPLE])
{
int i = 0, j = 0;
for (i = 0; i < FLOORS; i++)
{
for(j = 0; j < PEOPLE;j++)
{
cout << arrResult[i][j] << " ";
}
cout << " = " << arrClmib[i]<< endl;
}
}
void scan()
{
int i = 0, j = 0;
int nMin = MAX, nMinIndex = 0;
memset(arrResult, -1, sizeof(int)*PEOPLE*FLOORS);
for (i = 0; i < FLOORS; i++)
{
for(j = 0; j < PEOPLE;j++)
{
arrResult[i][j] = abs(i+1 - arrTarget[j]);
arrClmib[i] += arrResult[i][j];
}
if (nMin > arrClmib[i])
{
nMin = arrClmib[i];
nMinIndex = i;
}
}
print(arrResult);
cout << "\n========================================" << endl;
cout << "stop at: floor " << nMinIndex+1 << " clmib = " << nMin << endl;
}
void main()
{
int i = 0;
scan();
cin >> i;
}
测试结果:
2 5 8 9 4 = 28
1 4 7 8 3 = 23
0 3 6 7 2 = 18
1 2 5 6 1 = 15
2 1 4 5 0 = 12
3 0 3 4 1 = 11
4 1 2 3 2 = 12
5 2 1 2 3 = 13
6 3 0 1 4 = 14
7 4 1 0 5 = 17
========================================
stop at: floor 6 clmib = 11
复杂度为 O(N*N)
想法 II: 利用你多爬一层我就少爬一层的关系,找一个最优的解。
假设就三层楼 i-1, i, i+1,到i-1层总共会爬N1层,到i层会爬N2,到 i+1会爬N3
如果电梯停在i-1层,那么也就有N1层的楼不用爬了。总数也就 Y
-N1+N2+N3
如果电梯停在i+1层,那么也就有N3层的楼不用爬了。总数也就 Y+N1+N2
-N3
如果N1 > N2+N3那一定是停在i-1层合适,减去的楼层多了
如果N3 > N1+N2那一定是停在i+1层合适,减去的楼层多了
这样得到了算法II,先算出所有的要爬的楼层的总和,在按上面的计算方式每层向上计算。
代码:测试
假设一共有5个人分别去 3,6,9,10和5层
这里arrFloorPeople的数字表示到每一层的人数。
#include <iostream>
using namespace std;
#define FLOORS 10
int arrFloorPeople[FLOORS] = {0,0,1,0,1,1,0,0,1,1};
void Calc(int &nFloors, int& nFloorIndex)
{
int i = 0;
int N1 =0, N2 = 0, N3 = 0;
int nMin = 0, nTargetFloor = 0;
for (N1 = 0, N2 = arrFloorPeople[1], N3 = 0, i = 1; i < FLOORS; i++)
{
N3 += arrFloorPeople[i];
nMin += arrFloorPeople[i] * (i-1);
}
for (i = 2; i < FLOORS; i++)
{
if(N1+N2 <N3)
{
nTargetFloor = i;
nMin += (N1 + N2 - N3);
N1 += N2;
N2 = arrFloorPeople[i];
N3 -= arrFloorPeople[i];
}
else
break;
}
nFloors = nMin;
nFloorIndex = nTargetFloor+1;
}
void main()
{
int nFloors = 0;
int nFloorIndex = 0;
Calc(nFloors, nFloorIndex);
cout << "stop at: floor " << nFloorIndex << " clmib = " << nFloors << endl;
cin >> nFloors;
}
测试结果:
stop at: floor 6 clmib = 11