凸包算法(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 题目大意:有一个国王,要在自己的城堡周围建立围墙,要求围墙能把城堡全部围起来,并且围墙距离城堡的 ...
随机推荐
- DIAView组态软件笔记
1.为了节省成本,我们往往会在PLC将多个开关量整合到同一个word中,这样关联的变量可以从原有的16个变成现在的一个.这样做带来的麻烦就是需要我们在脚本中自己来解析出数据,通过对2求余(mod 2) ...
- 阿里云修改主机名(以centOS为例)
需要更改配置文件生效,修/etc/sysconfig/network里的 HOSTNAME=主机名(可自定义),重启生效. 如何修改? 1.[root@aliyunbaike ~]# cd /etc/ ...
- 聊聊c#与Python以及IronPython
简单说说这个意义.做了很久的c#,突然发现Python火了.就看看,估计这篇博文有点长,有点长,尽量包括主要的东西,还有点杂,浏览吧,选择自己喜欢的看看. 先看比较.网上一堆各种比较.但是主要比较语法 ...
- Vue--- 一点车项目
一点车项目 cli脚手架 + 组件化 +数据交互+路由指向+存入数据库 前端页面 cli脚手架的安装与搭建 创建对应包 页面组件化编辑 (共享组件:摘取出来一模一样的组件重用)(私有组件:在自 ...
- Django学习笔记4-csrf防护
1.CSRF验证失败. 请求被中断. 原因是django为了在用户提交表单时防止跨站攻击所做的保护 什么是 CSRF CSRF, Cross Site Request Forgery, 跨站点伪造请求 ...
- Sass变量及嵌套
1. 变量:SASS允许使用变量,所有变量以$开头. 变量声明:$highlight-color: #000; 注意:变量可以在css规则块定义之外存在.如下例子: $nav-color: #F90; ...
- Tornado异步与延迟任务
最近一直在研究Tornado异步操作,然而一番研究后发现要使一个函数异步化的最好方法就是采用相关异步库,但目前很多功能强大的库都不在此列.经过一番查找文档和搜索示范,终于发现了ThreadPoolEx ...
- laydate5.0 设置最大最小值
由于新版的laydate时间插件在初始化时已设置时间最大最小范围,且生成对象,无法重新渲染改变其日期最大最小值. 有网友经实验贴出如下方法可达成目的,故做记录. //开始时间 var startDat ...
- 嵌入式C语言自我修养 01:Linux 内核中的GNU C语言语法扩展
1.1 Linux 内核驱动中的奇怪语法 大家在看一些 GNU 开源软件,或者阅读 Linux 内核.驱动源码时会发现,在 Linux 内核源码中,有大量的 C 程序看起来“怪怪的”.说它是C语言吧, ...
- rails应用无法读取kafka数据报错Kafka::Error: Failed to find group coordinator
如果确保kafka中有数据,rails应用中却无法读取到,或报如下错误: Kafka::Error: Failed to find group coordinator 一般有两种情况,解决: ...