凸包算法(Graham扫描法)详解
先说下基础知识,不然不好理解后面的东西
两向量的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扫描法)详解的更多相关文章
- JVM垃圾回收算法及回收器详解
引言 本文主要讲述JVM中几种常见的垃圾回收算法和相关的垃圾回收器,以及常见的和GC相关的性能调优参数. GC Roots 我们先来了解一下在Java中是如何判断一个对象的生死的,有些语言比如Pyth ...
- 凸包模板——Graham扫描法
凸包模板--Graham扫描法 First 标签: 数学方法--计算几何 题目:洛谷P2742[模板]二维凸包/[USACO5.1]圈奶牛Fencing the Cows yyb的讲解:https:/ ...
- 【机器学习】【条件随机场CRF-2】CRF的预测算法之维特比算法(viterbi alg) 详解 + 示例讲解 + Python实现
1.CRF的预测算法条件随机场的预测算法是给定条件随机场P(Y|X)和输入序列(观测序列)x,求条件概率最大的输出序列(标记序列)y*,即对观测序列进行标注.条件随机场的预测算法是著名的维特比算法(V ...
- 凸包(Convex Hull)构造算法——Graham扫描法
凸包(Convex Hull) 在图形学中,凸包是一个非常重要的概念.简明的说,在平面中给出N个点,找出一个由其中某些点作为顶点组成的凸多边形,恰好能围住所有的N个点. 这十分像是在一块木板上钉了N个 ...
- c++ LeetCode(初级数组篇)十一道算法例题代码详解(一)
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/10940636.html 唉!最近忙着面试找实习,然后都是面试的很多是leetcode的算法题, ...
- 最短路径Floyd算法【图文详解】
Floyd算法 1.定义概览 Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被 ...
- KMP算法 Next数组详解
题面 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百 ...
- Dijkstra算法之 Java详解
转载:http://www.cnblogs.com/skywang12345/ 迪杰斯特拉算法介绍 迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主 ...
- $PollardRho$ 算法及其优化详解
\(PollardRho\) 算法总结: Pollard Rho是一个非常玄学的算法,用于在\(O(n^{1/4})\)的期望时间复杂度内计算合数n的某个非平凡因子(除了1和它本身以外能整除它的数). ...
- 凸包入门(Graham扫描法)(A - Wall POJ - 1113)
题目链接:https://cn.vjudge.net/contest/276359#problem/A 题目大意:有一个国王,要在自己的城堡周围建立围墙,要求围墙能把城堡全部围起来,并且围墙距离城堡的 ...
随机推荐
- Linux下的压缩解压缩命令
*.tar 解包:tar xvf FileName.tar 打包:tar cvf FileName.tar DirName (注:tar是打包,不是压缩!) ——————————————— *.gz ...
- java中exception和error有什么区别,运行时异常和一般异常有什么区别
1.exception和error都是继承了throwable类,在java中只有throwable类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型 2.ex ...
- 一个 Safari 的 new Date() bug
开发「bufpay.com 个人即时到账收款平台」后台套餐修改功能的时候碰到一个 new Date() bug. 既在 Safari 里面不支持 var t = new Date('2018-06-1 ...
- (Oracle)自定义调用AWR&ADDM
Oracle->自定义调用AWR&ADDM 需求描述: 前面设定每天自动生成AWR用于提供前一天的数据库状态信息,但因数据库和信息过多不利于直观检查.此次新增ADDM诊断. ADDM诊断 ...
- CentOS 6.8安装Ceph
机器规划 IP 主机名 角色 10.101.0.1 ceph01 mon admin mds 10.101.0.2 ceph02 ods 10.101.0.3 ceph03 ods 10.101.0. ...
- openssl windows平台编译库
首先感谢http://blog.csdn.net/YAOJINGKAO/article/details/53041165?locationNum=10&fps=1和https://www.cn ...
- python函数的四种参数传递方式
python中函数传递参数有四种形式 fun1(a,b,c) fun2(a=1,b=2,c=3) fun3(*args) fun4(**kargs) 四种中最常见是前两种,基本上一般点的教程都会涉及, ...
- URL和报文知识总结 ——1
第一部分:浏览器生成的消息 关键词:URL的解析 HTTP请求的生成 DNS服务器 1.URL(网址)的构成: 对于一个网址的解析: https://i.cnblogs.com/index.htm ...
- Go中处理文本格式
首先是xml 解析xml package main import ( "encoding/xml" //xml标准库 "fmt" "io/ioutil ...
- javascript sorting/ v8 sorting
https://github.com/mgechev/v8-sorting-test/tree/master/src/algorithms