您的位置:首页 > 编程语言

编程之美 - 爬楼梯问题

2016-01-26 21:21 225 查看
问题: 电梯在高峰时为了提高效率,当人们进入电梯选择好楼层后,根据算法只停在其中的一层。这个算法要求电梯里所有的人爬楼梯的总数最少。

想法 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

复杂度为 O(N)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: