先说下基础知识,不然不好理解后面的东西

两向量的X乘p1(x1,y1),p2(x2,y2)

p1Xp2如果小于零则说明  p1在p2的逆时针方向

如果大于零则说明 p1在p2的顺时针方向

struct node{
double x,y;
node friend operator -(node a,node b)//对减法符号进行重载
{
return {a.x-b.x,a.y-b.y};
}
}p[],s[];
double X(node a,node b){
return a.x*b.y-a.y*b.x;
}

这个方法很有用处。比如判断一个点是否在一条线段的左边还是右边,可以用X乘来判断,或者判断两条线段是否相交

接着说说凸包    Graham扫描法

1.在平面上一些散乱的点,首先  找找到这些点中处于最左下方的点

        for(int i=;i<=N;i++)
cin>>p[i].x>>p[i].y;
int k=;
for(int i=;i<=N;i++)
{
if(p[i].y<p[k].y||(p[k].y==p[i].y&&p[i].x<p[k].x))
k=i;
}
swap(p[],p[k]);

2.对这些点进行排序。把按照极角(polar angle)从小到大排序(以 p1为极点),极角相同的点按照到的距离从小到大排序。

int cmp(node a,node b)
{
double x=X(a-p[],b-p[]);//以p[1]为极点,通过X乘来判断 if(x>) return ;//让a处于b的顺时针
if(x==&&dis(a,p[])<dis(b,p[]))return ;//角度相同看距离
return ;
} sort(p+,p+N+,cmp);

3.再开一个结构体数组s 来储存凸包最外围的点,也就是结果,这个有点容易让人搞迷。

遍历剩下的点,while循环把发现不是凸包顶点的点移除出去,因为当逆时针遍历凸包时,我们应该在每个顶点向左转。因此当while循环发现在一个顶点处没有向左转时,就把该顶点移除出去。

至于如何判断向左向右则是根据叉积来判断,前面我们已经解决过这个问题了

double multi(node a,node b,node c)
{
return X(b-a,c-a);
}    s[]=p[];
s[]=p[];
int t=;
for(int i=;i<=N;i++)
{
// 发现在栈里边一个顶点处没有向左转时,就把该顶点移除出去
while(t>=&&multi(s[t-],s[t],p[i])<=) t--;
s[++t]=p[i];
}

这个是求凸包的周长的

hdu1392    http://acm.hdu.edu.cn/showproblem.php?pid=1392

算是模板题吧

#include<bits/stdc++.h>
using namespace std; struct point{
double x,y;
point friend operator -(point a,point b)
{return {a.x-b.x,a.y-b.y};}
}p[],s[];
double dis(point a,point b)
{
point c=a-b;
return sqrt(c.x*c.x+c.y*c.y);
}
double X(point a,point b)
{
return a.x*b.y-a.y*b.x;
}
int cmp(point a,point b)
{
double x=X(a-p[],b-p[]); if(x>) return ;
if(x==&&dis(a,p[])<dis(b,p[])) return ;
return ;
}
double multi(point p1,point p2,point p3)
{
return X(p2-p1,p3-p1);
}
int main()
{
int N;
while(scanf("%d",&N),N)
{
for(int i=;i<=N;i++) cin>>p[i].x>>p[i].y; if(N==)
{
printf("0.00\n");
continue;
}
else if(N==)
{
printf("%.2lf\n",dis(p[],p[]));
continue;
} int k=;
for(int i=;i<=N;i++)
if(p[i].y<p[k].y||(p[i].y==p[k].y&&p[i].x<p[k].x))k=i;
swap(p[],p[k]); sort(p+,p++N,cmp); s[]=p[];
s[]=p[];
int t=;
for(int i=;i<=N;i++)
{
while(t>=&&multi(s[t-],s[t],p[i])<=) t--;
s[++t]=p[i];
}
double sum=;
for(int i=;i<t;i++)
{
sum+=dis(s[i],s[i+]);
}
printf("%.2lf\n",sum+dis(s[],s[t]));
}
return ;
}

emmm  再来个求任意多边形的面积

struct Point {
double x, y;
}; //计算任意多边形的面积,顶点按照顺时针或者逆时针方向排列
double polygon_area(Point *p, int n)
{
if(n < ) return ; double sum = ;
p[n + ] = p[];
for(int i = ; i <= n; i++)
sum += p[i].x * p[i + ].y - p[i].y * p[i + ].x;//可以理解为不管这个多边形在哪,都以原点为分割点,就算原点在外面也可以算出,因为有正负可以抵消掉多余的
sum = fabs(sum / 2.0);
return sum;
}

再来个求面积均匀的多边形重心

需要把多边形以p[0]为分界点  分成n-2个三角形,求出这些三角形的重心(i,j),乘以该三角形的面积,如上图公式

#include<bits/stdc++.h>
using namespace std;
struct node{
double x,y;
node friend operator -(node a,node b)
{
return {a.x-b.x,a.y-b.y};
}
double friend operator *(node a,node b)//对*进行重载 node*node 相当于X乘
{
return a.x*b.y-a.y*b.x;
}
}a[];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=;i<=n;i++) cin>>a[i].x>>a[i].y; double S=,X=,Y=;
for(int i=;i<n;i++)
{
double x=(a[i]-a[])*(a[i+]-a[]);//这个乘和下面的不一样,这时X乘,求出三角形面积
X+=(a[].x+a[i].x+a[i+].x)*x;//重心(没除以3)乘以面积
Y+=(a[].y+a[i].y+a[i+].y)*x;
S+=x;
}
printf("%.2lf %.2lf\n",X/S/(double),Y/S/(double));//除以3为重心
}
return ;
}

凸包算法(Graham扫描法)详解的更多相关文章

  1. JVM垃圾回收算法及回收器详解

    引言 本文主要讲述JVM中几种常见的垃圾回收算法和相关的垃圾回收器,以及常见的和GC相关的性能调优参数. GC Roots 我们先来了解一下在Java中是如何判断一个对象的生死的,有些语言比如Pyth ...

  2. 凸包模板——Graham扫描法

    凸包模板--Graham扫描法 First 标签: 数学方法--计算几何 题目:洛谷P2742[模板]二维凸包/[USACO5.1]圈奶牛Fencing the Cows yyb的讲解:https:/ ...

  3. 【机器学习】【条件随机场CRF-2】CRF的预测算法之维特比算法(viterbi alg) 详解 + 示例讲解 + Python实现

    1.CRF的预测算法条件随机场的预测算法是给定条件随机场P(Y|X)和输入序列(观测序列)x,求条件概率最大的输出序列(标记序列)y*,即对观测序列进行标注.条件随机场的预测算法是著名的维特比算法(V ...

  4. 凸包(Convex Hull)构造算法——Graham扫描法

    凸包(Convex Hull) 在图形学中,凸包是一个非常重要的概念.简明的说,在平面中给出N个点,找出一个由其中某些点作为顶点组成的凸多边形,恰好能围住所有的N个点. 这十分像是在一块木板上钉了N个 ...

  5. c++ LeetCode(初级数组篇)十一道算法例题代码详解(一)

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/10940636.html 唉!最近忙着面试找实习,然后都是面试的很多是leetcode的算法题, ...

  6. 最短路径Floyd算法【图文详解】

    Floyd算法 1.定义概览 Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被 ...

  7. KMP算法 Next数组详解

    题面 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百 ...

  8. Dijkstra算法之 Java详解

    转载:http://www.cnblogs.com/skywang12345/ 迪杰斯特拉算法介绍 迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主 ...

  9. $PollardRho$ 算法及其优化详解

    \(PollardRho\) 算法总结: Pollard Rho是一个非常玄学的算法,用于在\(O(n^{1/4})\)的期望时间复杂度内计算合数n的某个非平凡因子(除了1和它本身以外能整除它的数). ...

  10. 凸包入门(Graham扫描法)(A - Wall POJ - 1113)

    题目链接:https://cn.vjudge.net/contest/276359#problem/A 题目大意:有一个国王,要在自己的城堡周围建立围墙,要求围墙能把城堡全部围起来,并且围墙距离城堡的 ...

随机推荐

  1. MySQL优化之Explain命令解读

    简述: explain为mysql提供语句的执行计划信息.可以应用在select.delete.insert.update和place语句上.explain的执行计划,只是作为语句执行过程的一个参考, ...

  2. Linux -- cal/bc/LANGE与帮助文档

    cal 显示日历命令 使用cal命令,显示日历 cal [month] [year] 1.显示当前的日历 [root@localhost ~]# cal 一月 日 一 二 三 四 五 六 2.显示指定 ...

  3. HTML表格属性及简单实例

    这里主要总结记录下表格的一些属性和简单的样式,方便以后不时之需. 1.<table> 用来定义HTML的表格,具有本地属性 border 表示边框,border属性的值必须为1或空字符串( ...

  4. HTML基础之常用标签

    Meta 标签介绍 Meta的属性有两种:name和http-equiv name属性用于描述网页,对应于content <meta name="Generator" con ...

  5. 08.nextcloud搭建

    由于公司用的nfs文件共享系统满足不了权限需求,测试nextcloud是否符合要求 参考博客: https://www.cnblogs.com/davidz/articles/9686716.html ...

  6. Kaggle比赛总结

    做完 Kaggle 比赛已经快五个月了,今天来总结一下,为秋招做个准备. 题目要求:根据主办方提供的超过 4 天约 2 亿次的点击数据,建立预测模型预测用户是否会在点击移动应用广告后下载应用程序. 数 ...

  7. java并发实战:连接池实现

    池化技术简介 在我们使用数据库的过程中,我们往往使用数据库连接池而不是直接使用数据库连接进行操作,这是因为每一个数据库连接的创建和销毁的代价是昂贵的,而池化技术则预先创建了资源,这些资源是可复用的,这 ...

  8. npm 取消代理 npm config delete proxy

    今天在安装electron时设置了代理,发现再npm install 安装别的总是装不上,只好取消代理. npm 取消代理 npm config delete proxy

  9. nginx 日志记录 自定义详解(分析上报用)

    nginx 日志记录 自定义详解   1.log_format 普通格式 log_format main '$remote_addr - $remote_user [$time_local] $req ...

  10. sample采样倾斜key并单独进行join代码

    /** * sample采样倾斜key单独进行join */ JavaPairRDD<Long, String> sampledRDD = userid2PartAggrInfoRDD.s ...