编程之美 - 爬楼梯问题
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层
测试结果:
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
![](http://img.blog.csdn.net/20160126212005363?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
如果电梯停在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的数字表示到每一层的人数。
测试结果:
stop at: floor 6 clmib = 11
复杂度为 O(N)
想法 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)
相关文章推荐
- php函数call_user_func和call_user_func_array详解
- Qt之自定义界面(右下角冒泡)
- Qt之自定义界面(右下角冒泡)
- 基于MyEclipse搭建maven+springmvc图文教程(含源码)
- CPP 1014 Fans数
- 二分查找的实现
- Spring MVC 之请求处理方法可接收参数(三)
- python 图像识别
- Elasticsearch过滤与聚合的先后顺序java实现
- 【转】github如何删除一个仓库
- java web 过滤器
- 跟siki老师学C#第九天(满满的都是练习)
- Java对象判等,重写equals方法
- Matlab----在fig中插入Latex公式
- Matlab-----更改Matlab图中颜色
- Java 线程 —— 基础篇
- 编程题
- java下载excel在firefox中中文名称乱码
- 小甲鱼零基础学Python课后习题第25课
- SpringMVC对RESTful支持