POJ 2187 旋转卡壳求凸包的直径
2016-07-26 21:09
603 查看
首先推荐一个详细讲解旋转卡壳的博客 http://blog.csdn.net/acmaker
这个博客里面涵盖了大部分常用的旋转卡壳问题。
首先这个题目大概是说给你N个点(N<50000),求解两点间的最大距离。首先如果枚举每一个点,O(n^2),显然是会超时的,那么这边运用旋转卡壳算法能在O(n)时间内算出,单求凸包时排序花费O(nlogn),所以复杂度是O(nlogn)+O(n)。讲道理,这题如果按照分治的思想应该也能跑过。
这个博客里面涵盖了大部分常用的旋转卡壳问题。
首先这个题目大概是说给你N个点(N<50000),求解两点间的最大距离。首先如果枚举每一个点,O(n^2),显然是会超时的,那么这边运用旋转卡壳算法能在O(n)时间内算出,单求凸包时排序花费O(nlogn),所以复杂度是O(nlogn)+O(n)。讲道理,这题如果按照分治的思想应该也能跑过。
#include <iostream> #include <vector> #include <algorithm> #include <cmath> #include <cstdio> using namespace std; #define MAX_N 50010 #define M_PI 3.14159265358979323846 typedef int type_xy; struct P { type_xy x, y; P() {} P(type_xy x, type_xy y) : x(x), y(y) {} P operator + (P p){ return P(x + p.x, y + p.y); } P operator - (P p){ return P(x - p.x, y - p.y); } P operator * (type_xy d){ return P(x*d, y*d); } bool operator < (const P& a) const { if (x != a.x) return x < a.x; else return y < a.y; } type_xy dot(P p) { return x*p.x + y*p.y; } type_xy det(P p) { return x*p.y - y*p.x; } }; // 字典序比较 bool cmp_x(P a, P b) { if (a.x != b.x) return a.x < b.x; return a.y < b.y; } // 求凸包 vector<P> convex_hull(P *ps, int n) { sort(ps, ps + n, cmp_x); int k = 0; // 凸包的顶点数 vector<P> qs(n * 2); // 构造中的凸包 // 构造凸包的下侧 for (int i = 0; i < n; ++i) { while (k > 1 && (qs[k - 1] - qs[k - 2]).det(ps[i] - qs[k - 1]) <= 0) --k; qs[k++] = ps[i]; } // 构造凸包的上侧 for (int i = n - 2, t = k; i >= 0; --i) { while (k > t && (qs[k - 1] - qs[k - 2]).det(ps[i] - qs[k - 1]) <= 0) --k; qs[k++] = ps[i]; } qs.resize(k - 1); return qs; } // 距离的平方 double dist(P p, P q) { return sqrt((double)(p - q).dot(p - q)); } // 求解凸包对踵点最大距离 double max_distance(P *ps, int N) { vector<P> qs = convex_hull(ps, N); int n = qs.size(); if (n == 2) { return dist(qs[0], qs[1]); // 特别处理凸包退化的情况 } int i = 0, j = 0; // 某个方向上的对踵点对 // 求出x轴方向上的对踵点对 for (int k = 0; k < n; k++) { if (!cmp_x(qs[i], qs[k])) i = k; if (cmp_x(qs[j], qs[k])) j = k; } double res = 0; int si = i, sj = j; while (i != sj || j != si) // 将方向逐步旋转180度 { res = max(res, dist(qs[i], qs[j])); // 判断先转到边i-(i+1)的法线方向还是边j-(j+1)的法线方向 if ((qs[(i + 1) % n] - qs[i]).det(qs[(j + 1) % n] - qs[j]) < 0) { i = (i + 1) % n; // 先转到边i-(i+1)的法线方向 } else { j = (j + 1) % n; // 先转到边j-(j+1)的法线方向 } } return res; } P ps[MAX_N]; int main() { int n; while(~scanf("%d",&n)) { for(int i=0;i<n;i++) { scanf("%d%d",&ps[i].x,&ps[i].y); } double x=max_distance(ps,n); printf("%d\n",(int)(x*x)); } return 0; }
相关文章推荐
- 如何阅读一篇论文
- 如何用PyCharm运行Scrapy
- 微信公众号开发教程[014]-帐号管理
- UVA 146 ID Codes
- 正则使用的几种形态
- hd 2141 Can you find it?(二分)
- 后web时代,你的网站更新了https了吗?
- abp记录1
- abp记录1
- KNN算法
- HDU1502 Regular Words(DP+大数模拟)
- Eclipse Java注释模板设置详解
- 严重: Field 'id' doesn't have a default value Exception in thread "main" org.hibernate.exception.Gener
- 多媒体-FFMPEG-Anroid-采集-PCM-MP3
- POJ 2947 Widget Factory <高斯消元同余线性方程>
- Spring Boot 属性配置和使用
- STL之优先队列
- Spring-Spring框架基本配置文件解析
- UVA 11111-Generalized Matrioshkas
- Android 内存溢出解决方案(OOM)