凸包算法(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 题目大意:有一个国王,要在自己的城堡周围建立围墙,要求围墙能把城堡全部围起来,并且围墙距离城堡的 ...
随机推荐
- libstagefright 音视频同步方案
1:音视频数据都有一个list,用于存放解码后的数据: List mFilledBuffers; 2:解码后的音视频数据不断的往list中存放,不做音视频同步方面的时间上控制 mFille ...
- Ubuntu下配置安装telnet server
1.安装xinetd 以及telnetd # apt-get install xinetd telnetd 2.配置文件/etc/inetd.conf #vi /etc/inetd.conf # St ...
- JS异步编程 (2) - Promise、Generator、async/await
JS异步编程 (2) - Promise.Generator.async/await 上篇文章我们讲了下JS异步编程的相关知识,比如什么是异步,为什么要使用异步编程以及在浏览器中JS如何实现异步的.最 ...
- direct path write 等待事件导致数据库hang
同事反应十几分钟前数据库好像挂起了一会,让我排查数据库是否存在什么问题. 第一反应看当前数据库还是否有什么等待事件,结果有direct path write等待事件. 于是抓了问题时间段20分钟的AS ...
- jQuery入门简单实现反选与全选
//html代码<input type="checkbox" id= 'all' value="全选"> 选择全部 一键上路 <input t ...
- 《DOM编程艺术》读书笔记<概述>
作为一名前端开发工程师,学习的过程中总少不了各种各样的书籍,作为新手如何在众多书籍中选到适合自己的呢,我们今天先来谈谈<DOM编程艺术>这本书. 其实呢大部分书都是好书,就像LOL中大部分 ...
- Jquery之倒计时计算
setInterval(); function setDate(setTime){ var date = new Date();//获取系统当前时间 )+)+"-"+date. ...
- C# Server.MapPath的使用方法
(1)WebForm中: HttpContext.Current.Server.MapPath("~/Files/car/"); (2)Mvc中: Server.MapPath() ...
- FileBeats安装
FileBeats安装 FileBeats官方下载链接: https://www.elastic.co/downloads/beats/filebeat 也可以直接使用以下命令下载(文章下载目录一概为 ...
- Mongodb从库配置
1. 先以master方式启动mongodb 2. 导入主库的数据文件:/data/mongodb-3.0.12/bin/mongorestore /data/tmp/mongodbbak/ 3. 关 ...