中位数应用:输油管道问题--快速排序、改进、变种
2016-05-18 19:07
267 查看
问题描述:某石油公司计划建造一条由东向西的主输油管道。该管道要穿过一个有n口油井的油田。从每口油井都要有一条输油管道沿最短路经(或南或北)与主管道相连。示意如下所示。如果给定n口油井的位置, 即它们的x坐标(东西向)和y坐标(南北向), 应如何确定主管道的最优位置, 即使各油井到主管道之间的输油管道长度总和最小的位置?
问题分析:问题可以抽象为给定n个点坐标,如何确定一条平行于x轴的直线,使得所有的点到直线的距离和最短。进一步简化为只提取n个点的纵坐标,保存进数组中,目标是确定直线的纵坐标使得距离和最短。
解决方案:给定点的个数可能为奇数或偶数,两种情况对直线的位置确定影响不同。
对于偶数点情况:当直线在a2-a3之间的时候,距离和D=(a3-a2)+(a4-a1),当直线在别的位置比如a1-a2时,距离和D=(a3-a2)+(a4-a1)+d,其中d为偏移量。我们会发现只有直线位置属于[a2,a3]时,距离和才会最小,而且在[a2,a3]任意位置,距离和都是固定的。所以没有必要将直线取值在a2和a3的正中间,取a2和a3能有相同的效果,相当于a2和a3中间位置取整,这就说明找到n个点的中位数即可。
对于奇数点情况:和偶数点相同,也是找中位数。直线位于a2时,距离和D=a3-a1,当直线偏离a2,位于a1-a2间时,距离和D=a3-a1+d,d为a2偏移量。也能说明只有直线位于中位数位置时,距离和最短,是我们要找的位置。
详细细节:对于输入的数据,提取纵坐标保存到数组中,然后排序,找到中位数。众多排序算法中,快排平均性能最优,故先选择快排,然后提取中位数。
实现代码:
快速排序的改进:随机选择算法。
在选择基数位的时候,不是每次都选择第一个数,而是以随机的方式产生表示任意位置的随机数来作为基数。从概率角度,这种做法不会达到最坏的时间复杂度O(n2)。
输油管道问题变种:
管道不一定水平,可以任意方向旋转
本质上相当于坐标轴旋转确定新的坐标。新的油井纵坐标为y=y0cos(a)+x0sin(a)。原理和水平放置相同。通过遍历a度数(度数a取值范围0-180),每遍历一个度数就执行中位数查找,确定距离和Di,然后在所有的D中找最小的。
油井有权重
若考虑每个油井即使和管道距离相同,但每个油井代价不同。此时该如何建立管道保证总代价最小。问题会转换为带权中位数问题。
拓展:邮局选址问题
输油管道问题是一维的邮局选址问题。(待补充)
问题分析:问题可以抽象为给定n个点坐标,如何确定一条平行于x轴的直线,使得所有的点到直线的距离和最短。进一步简化为只提取n个点的纵坐标,保存进数组中,目标是确定直线的纵坐标使得距离和最短。
解决方案:给定点的个数可能为奇数或偶数,两种情况对直线的位置确定影响不同。
对于偶数点情况:当直线在a2-a3之间的时候,距离和D=(a3-a2)+(a4-a1),当直线在别的位置比如a1-a2时,距离和D=(a3-a2)+(a4-a1)+d,其中d为偏移量。我们会发现只有直线位置属于[a2,a3]时,距离和才会最小,而且在[a2,a3]任意位置,距离和都是固定的。所以没有必要将直线取值在a2和a3的正中间,取a2和a3能有相同的效果,相当于a2和a3中间位置取整,这就说明找到n个点的中位数即可。
对于奇数点情况:和偶数点相同,也是找中位数。直线位于a2时,距离和D=a3-a1,当直线偏离a2,位于a1-a2间时,距离和D=a3-a1+d,d为a2偏移量。也能说明只有直线位于中位数位置时,距离和最短,是我们要找的位置。
详细细节:对于输入的数据,提取纵坐标保存到数组中,然后排序,找到中位数。众多排序算法中,快排平均性能最优,故先选择快排,然后提取中位数。
实现代码:
#include<iostream> #include<vector> #define len 10 using namespace std; void quickSort(int[] , int, int); int main(){ vector<int> list; //读入n个油井纵坐标的位置 list.push_back(5); list.push_back(9); list.push_back(2); list.push_back(9); //cout << "容器大小为: " << list.size() << endl; int array[len] = {}; //将向量转换为数组,主要考虑到传参时,数组是指针。 for (int i = 0; i < list.size(); i++) array[i] = list.at(i); quickSort(array, 0, list.size()-1); //cout<<list.at(1)<<endl; //list.at(1) = 4; for (int i = 0; i < list.size(); i++) cout << array[i] << endl; cout<<"输油管道放置位置坐标:y=" << array[list.size() / 2-1]<<endl; } void quickSort(int a[], int left, int right) { if (left<right) { int i = left; int j = right; int x = a[i]; while (i<j) { while (i<j&&a[j]>x) j--; if (i<j){ a[i] = a[j]; i++; } while (i<j&&a[i]<x) i++; if (i<j){ a[j] = a[i]; j--; } } a[i] = x; quickSort(a, left, i - 1); quickSort(a, i + 1, right); } } 结果: 油井纵坐标:2 油井纵坐标:5 油井纵坐标:9 油井纵坐标:9 输油管道放置位置坐标:y=5
快速排序的改进:随机选择算法。
在选择基数位的时候,不是每次都选择第一个数,而是以随机的方式产生表示任意位置的随机数来作为基数。从概率角度,这种做法不会达到最坏的时间复杂度O(n2)。
输油管道问题变种:
管道不一定水平,可以任意方向旋转
本质上相当于坐标轴旋转确定新的坐标。新的油井纵坐标为y=y0cos(a)+x0sin(a)。原理和水平放置相同。通过遍历a度数(度数a取值范围0-180),每遍历一个度数就执行中位数查找,确定距离和Di,然后在所有的D中找最小的。
油井有权重
若考虑每个油井即使和管道距离相同,但每个油井代价不同。此时该如何建立管道保证总代价最小。问题会转换为带权中位数问题。
拓展:邮局选址问题
输油管道问题是一维的邮局选址问题。(待补充)
相关文章推荐
- 51.链表中环的入口结点
- 解决No result defined for action action.bookstore.AddInfoAction and result input
- android canvas常用的方法解析(一)
- Spring的配置文件找不到元素 'beans' 的声明
- Spring框架简介
- 单项目多 servlet 的xml 配置
- springmvc 首次启动方法
- Python之编码规范
- 递归锁
- 探索《How Tomcat Works》心得(三)--容器
- 写给后端程序员的HTTP缓存原理介绍
- git 回滚
- 使用 Log4j、ActiveMQ 和 Spring 实现异步日志
- 第11周补充(2)职员有薪水了!
- 336(see). Palindrome Pairs 5.(see)
- Android Launcher分析和修改1——Launcher默认界面配置(default_workspace)
- 判断客户端是否使用了代理
- 6.5+3
- 沙盒文件管理
- 二叉搜索树与双向链表