【算法学习笔记】36.凸包 求最大两点距离 SJTU OJ 1244 Date A Live
2015-04-29 19:17
465 查看
Description
某助教有好多好多妹纸,其中不乏来自五道口与东川路等男子职业技术学校的。然而,遥远的距离让他不得不花费大量的时间奔波于众多城市之间。为了更好地安排自己的约会计划,他想知道最远的两只妹纸之间的距离是多少。Input Format
第一行有一个整数n,表示妹纸的数量。接下来n行,每行两个实数x,y,表示妹纸的坐标(假定在一个平面直角坐标系上)。对于80%的数据,n<=2000对于90%的数据,n<=10000对于100%的数据,n<=100000Output Format
输出一个实数,表示最远的妹纸间的欧几里得距离(即直线距离)。答案保留4位小数。Sample Input
3 1 1 0 0 10 1
Sample Output
10.0499数学模型就是求一个点集最远两个点的距离大小.想法是先用Graham扫描法来建立凸包集合.
然后有两条路,其中一个就是Cn2枚举出任意两个点 求出距离
另一个是用传说中的旋转卡壳法来求.复杂度为On ,基本思想就是旋转寻找和凸包之边的最远的点,由于凸包的凸性质,导致这个最远点的旋转方向和边的旋转方向一致,所以压缩至On以下代码是用数组实现的凸包+Cn2方法,
数组实现比STL的vector要快很多,而且也比较容易看懂.
几个值得注意的地方是
1.基点的选择, 选择最左下的点,还是选最低点里偏左的
2.比较的方法, 余弦定理还是外积判断?
3.栈顶指针的竖直和栈长度的关系...= =[/code]
#include <iostream> #include <cmath> #include <algorithm> #include <cstdio> using namespace std; struct Point { double x, y; }; Point pointSet[100005]; int convexHull[100005];//凸包只要存储点的ID即可 int ps_len=0;//点集的大小 int ch_len=0;//凸包的栈指针 ostream& operator << (ostream &out, const Point& p) { out <<'('<<p.x<<','<<p.y<<')'<<endl ; return out; } //计算外积 负表示顺时针 正表示逆时针 0表示共线 inline double crossProduct(const Point &p1, const Point &p2,const Point &p0){ return (p1.x-p0.x)*(p2.y-p0.y) - (p1.y-p0.y)*(p2.x-p0.x); } //返回正数表示要把两个数进行交换 也就是把b放在a前面 逆时针排序 int cmpTwoPoints(const void *a, const void *b){ Point* p1 = (Point*) a; Point* p2 = (Point*) b; //注意:此时基点已经是pointSet[0] //第一种方法利用余弦定理来进行判断 //第二种方法利用叉乘来表示 如果 < p0,p1 , p0,p2 >是负数 则表示指向纸面内部 也就是顺时针 double res = crossProduct(*p1, *p2, pointSet[0]); if(res<0) return 1; if(res == 0 and p2->x < p1->x)//如果共线且p2更近 return 1; return -1; } // inline Point CH(int CHid) // { // return pointSet[convexHull[CHid]]; // } //建立凸包 void BuildConvexHull(){ //Step1 找到基准点 最下偏左的点 int basePoint=0; for (int i = 1; i < ps_len; ++i) { //if( pointSet[i].y < pointSet[basePoint].y or (pointSet[i].y==pointSet[basePoint].y and pointSet[i].x<pointSet[basePoint].x) ) if( pointSet[i].x < pointSet[basePoint].x or (pointSet[i].x==pointSet[basePoint].x and pointSet[i].y<pointSet[basePoint].y) ) basePoint = i; } swap(pointSet[basePoint],pointSet[0]);//把基点换到ps的第一个位置 //Step2 把pointSet里的点按照他们与基点的连线与x轴的夹角的大小进行排序 qsort(pointSet+1,ps_len-1,sizeof(Point),cmpTwoPoints);//不算基点 进行排序 // PrintPS(); //Step3 开始build凸包 convexHull[0] = 0;//基点肯定是凸包上的第一个点 入栈 convexHull[1] = 1;//预设第一个非基点的点也是凸包上的点 入栈 convexHull[2] = 2; ch_len = 2;//指针指向栈顶元素 //开始DFS --> 栈 for (int i = 3; i < ps_len ; ++i)//研究剩余的所有点 { //假如让它入栈 它可以和 前一个点 前前一个点 是逆时针旋转的 那么就暂时可以加入 否则 踢出上x个点 直到可以继续 while(ch_len > 0 and crossProduct(pointSet[convexHull[ch_len]],pointSet[i],pointSet[convexHull[ch_len-1]]) < 0) ch_len--;//抛弃这个凹点 convexHull[++ch_len] = i;//暂时让此点入栈 } } inline double _dis(Point p1, Point p2){ return sqrt(pow((p1.x-p2.x),2)+pow((p1.y-p2.y),2)); } inline double _max(double a,double b){ return a>b ? a : b; } double Cal(){ double res = 0; for (int i = 0; i < ch_len+1-1; ++i) for (int j = i+1; j < ch_len+1 ; ++j) res = _max(res,_dis(pointSet[convexHull[i]],pointSet[convexHull[j]])); return res; } int main(int argc, char const *argv[]) { cin>>ps_len; for (int i = 0; i < ps_len; ++i) scanf("%lf %lf",&pointSet[i].x,&pointSet[i].y); BuildConvexHull(); printf("%.4lf",Cal()); return 0; }View Code
几个相关博客:
http://www.cnblogs.com/devymex/archive/2010/08/09/1795392.html http://blog.csdn.net/hackbuteer1/article/details/7484746
相关文章推荐
- 【算法学习笔记】72.LCS 最大公公子序列 动态规划 SJTU OJ 1065 小M的生物实验1
- 【算法学习笔记】77.双线棋盘 动态规划 SJTU OJ 1263 纸来纸去
- 【算法学习笔记】38.最短路问题 SJTU OJ 1105 path
- 【算法学习笔记】54.约瑟夫问题 模拟、逆推动规 SJTU OJ 1038 二哥的约瑟夫
- 【算法学习笔记】67.状态压缩 DP SJTU OJ 1383 畅畅的牙签袋
- 【算法学习笔记】80.二维动态规划 SJTU OJ 3022 二哥要翘课
- 【算法学习笔记】42.正反DP 填充问题 SJTU OJ 1285 时晴时雨
- 【算法学习笔记】64. 枚举法 SJTU OJ 1381 畅畅的牙签
- 【算法学习笔记】86.栈 中缀表达式 SJTU OJ 1033 表达式计算
- 【算法学习笔记】61.回溯法 DFS SJTU OJ 1106 sudoku
- 【算法学习笔记】27.动态规划 解题报告 SJTU OJ 1254 传手绢
- 【算法学习笔记】81.动态规划 分类讨论 SJTU OJ 1075 括号匹配升级
- 【算法学习笔记】70.回文序列 动态规划 SJTU OJ 1066 小M家的牛们
- 【算法学习笔记】46.拓扑排序 优先队列 SJTU OJ 3010 Complicated Buttons
- 【算法学习笔记】50.字符串处理 SJTU OJ 1361 丁姐的周末
- 【算法学习笔记】39.字符串处理 单词分割 SJTU OJ 1302 缩进格式
- 【算法学习笔记】33.在线算法 SJTU OJ 1006 求和游戏
- 【算法学习笔记】52.一道题的三种方法..二分答案、动态规划、计算几何 SJTU OJ 1250 BestSubsequence
- 【算法学习笔记】65. 双向扫描 SJTU OJ 1382 畅畅的牙签盒
- 【算法学习笔记】49.暴力穷举 BFS 剪枝 SJTU OJ 1357 相邻方案