POJ 2187 平面最远点对 凸包入门
2017-09-25 00:24
459 查看
点击打开链接题目大意: 给出n个点,求出最远的两个点之间的距离思路:由于数据范围很大,暴力肯定不可以了,考虑平面的最远点对一定在凸包上(这点可以反证法来证明)。那么我们求出凸包上所有的点然后枚举凸包上的点就可以了.这里采用Graham扫描算法,复杂度nlogn.
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <vector> using namespace std; const int MAXN = 50000 + 5; struct P{ int x, y; }; P p[MAXN]; int n; //求两点之间的距离 int dis(P a, P b) { return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y); } /*计算叉积 判断点和直线的方向用叉积 若P1×p2 >0 则p1在p2的顺时针方向. <0 p1在p2的逆时针方向 = 0 共线 */ int cross(P a, P b, P c) { return (a.x - c.x) * (b.y - c.y) - (b.x - c.x) * (a.y - c.y); } //极角排序 bool cmp(P a, P b) { int x = cross(p[0],a,b); if(x > 0 || (x == 0 && dis(a, p[0]) < dis(b, p[0]))) return 1; return 0; } vector<P> Graham() { vector<P> stk(n);//存凸包 int k = 0; //Graham 算法 for (int i = 0; i < n; i++) { while (k > 1 && (cross(p[i], stk[k-2], stk[k-1])) <= 0) k--; stk[k++] = p[i]; } stk.resize(k);//调整正确的凸包顶点数 return stk; } int main() { while (~scanf("%d", &n)) { int ans = 0, rp = 0;//rp用于临时保存最左下点的下标 //输入 for (int i = 0; i < n; i++) { scanf("%d%d", &p[i].x, &p[i].y); if(p[rp].y > p[i].y || (p[rp].y == p[i].y && p[rp].x > p[i].x))//找最左下的点 rp = i; } //极角排序 swap(p[rp], p[0]);//初始化,方便cmp过程 sort(p + 1, p + n, cmp); //Graham Scan构成凸包 vector<P> stk = Graham(); //暴力求解 for (int i = 0; i < stk.size(); i++) { for (int j = 0; j < i; j++) ans = max(ans, dis(stk[i], stk[j])); } cout<<ans<<endl; } return 0; }
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int mod=1e9+7; const int maxn=5e4+5; struct node { int x,y; }a[maxn],sta[maxn]; //求亮点之间距离的平方. int dis(node n1,node n2) { return (n1.x-n2.x)*(n1.x-n2.x)+(n1.y-n2.y)*(n1.y-n2.y); } //计算叉积 int det(int x1,int y1,int x2,int y2) { return x1*y2-x2*y1; } //判断点和直线的方向用叉积 //若P1×p2 >0 则p1在p2的顺时针方向. //<0 p1在p2的逆时针方向 //= 0 共线 int cross(node a,node n1,node n2) { return det(n1.x-a.x,n1.y-a.y,n2.x-a.x,n2.y-a.y); } //极角排序 bool cmp(node n1,node n2) { //a[0]为纵坐标最小的点一定在凸包上,以它为原点进行极角排序 int k = cross(a[0],n1,n2); if(k > 0) return 1;//角度小的排在前面 //若共线则距离a[0]距离近的在前面. if(k == 0 && dis(a[0],n1) < dis(a[0],n2)) return 1; return 0; } void solve(node *ch,int len) { int ans = 0; for(int i = 0;i <= len;++i) { for(int j = i + 1;j <= len;++j) { ans = max(ans,dis(ch[i],ch[j])); } } cout<<ans<<endl; } //最后栈中存的点就是凸包上的点. void Graham(int n) { int i,head; for(i = 1;i < n;++i) //先找到最下面的那个点作为原点. if(a[i].x < a[0].x || (a[i].x == a[0].x && a[i].y < a[0].y)) swap(a[0],a[i]); sort(a+1,a+n,cmp);//极角排序 a = a[0]; sta[0] = a[0];//最下面的一个点和第二个点一定在凸包上. sta[1] = a[1]; sta[2] = a[2]; head = 2; //Graham 算法 for(int i = 3;i < n;++i) { while(head >= 2) { int fu = cross(sta[head - 1],sta[head],a[i]); if(fu < 0) head--; else if(fu == 0 && dis(sta[head - 1],a[i]) > dis(sta[head - 1],sta[head])) head--; else break; } sta[++head] = a[i]; } solve(sta,head); } int main(){ int n; while(scanf("%d",&n) > 0) { for(int i = 0;i < n;++i) { scanf("%d %d",&a[i].x,&a[i].y); } Graham(n); } return 0; }
相关文章推荐
- poj 2187 求平面最远点对 快速凸包 旋转卡壳
- poj 2187 凸包+平面上点之间最大距离
- POJ 2187 Beauty Contest (平面最远点对 凸包+旋转卡壳 推荐)
- poj 2187 计算几何入门题 凸包
- 【凸包直径&平面最远点对&对锺点(旋转卡壳)】poj 2187 Beauty Contest
- 【凸包】poj 2187 Beauty Contest (旋转卡壳求平面最远点对)
- POJ 2187(凸包GrahamScan扫描+极角排序+平面最远点对)
- poj 2187 Beauty Contest (凸包)
- poj2187-Beauty Contest 求凸包最远距离(旋转卡壳算法模板题)
- poj 2187 Beauty Contest(二维凸包旋转卡壳)
- poj 2187 Beauty Contest , 旋转卡壳求凸包的直径的平方
- POJ-2187--Beauty Contest---凸包
- poj 2187:Beauty Contest(计算几何,求凸包,最远点对)
- POJ-2187-凸包
- Poj 2187 Beauty Contest_旋转凸包卡壳
- poj_2187求凸包直径
- poj 2187(凸包+旋转卡壳)
- Poj2187 凸包求最大距离
- POJ 2187 Beauty Contest(凸包&&平面最远点对)
- poj 2187【凸包求最远距离】