首先肯定是构造一个完整的凸包包括所有的点,那么要使得刚好有两个点在外面,满足这个条件的只有三种情况。

1.两个在凸包上但是不连续的两个点。

2.两个在凸包上但是连续的两个点。

3.一个在凸包上,还有一个在这个点去掉后这段新凸包边上的一个点。

如何快速的截取新凸包的点是谁呢,我们可以将整个凸包划分区域,每个点删掉后,只可能在这块区域内选择新的点。那么我们就可以随机在凸包内部选择一个点,我使用的是凸包的重心作为坐标原点o,那么整个凸包移到原点处,然后在这个点的左侧和右侧的三角形区域内才是有可能构成新凸包边上的点,那我们只需要暴力枚举这部分内的点重构这条凸包边。那么第一第二种情况可以通过这个处理,第三种情况其实就是第一种情况套了第一种情况,那么就限暴力处理第一种情况的新凸包边,再在新凸包上继续分割三角区域,最后重构新凸包边中的新凸包边。

极角排序的时候细节处理有点坑,注意选择区域范围的角度相对大小,大型模拟题.... or

k点为重心

 //      ——By DD_BOND

 //#include<bits/stdc++.h>
//#include<unordered_map>
//#include<unordered_set>
#include<functional>
#include<algorithm>
#include<iostream>
//#include<ext/rope>
#include<iomanip>
#include<climits>
#include<cstring>
#include<cstdlib>
#include<cstddef>
#include<cstdio>
#include<memory>
#include<vector>
#include<cctype>
#include<string>
#include<cmath>
#include<queue>
#include<deque>
#include<ctime>
#include<stack>
#include<map>
#include<set> #define fi first
#define se second
#define pb push_back
#define MP make_pair #pragma GCC optimize(3)
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") using namespace std; typedef long double db;
typedef long long ll;
typedef pair<db,db> Pd;
typedef pair<int,int> P;
typedef pair<ll,ll> Pll; const db eps=1e-;
const int MAXN=1e6+;
const db pi=acos(-1.0);
const ll INF=0x3f3f3f3f3f3f3f3f; inline int dcmp(db x){
if(fabs(x)<eps) return ;
return (x>? : -);
} inline db Sqrt(db x){
return x>? sqrt(x): ;
} inline db sqr(db x){ return x*x; } struct Point{
db x,y,ang;
Point(){ x=,y=; }
Point(db _x,db _y):x(_x),y(_y){}
void input(){
double _x,_y;
scanf("%lf%lf",&_x,&_y);
x=_x,y=_y;
}
bool operator ==(const Point &b)const{
return (dcmp(x-b.x)==&&dcmp(y-b.y)==);
}
bool operator !=(const Point &b)const{
return !((dcmp(x-b.x)==&&dcmp(y-b.y)==));
}
bool operator <(const Point &b)const{
return (dcmp(x-b.x)==? dcmp(y-b.y)< : x<b.x);
}
Point operator +(const Point &b)const{
return Point(x+b.x,y+b.y);
}
Point operator -(const Point &b)const{
return Point(x-b.x,y-b.y);
}
Point operator *(db a){
return Point(x*a,y*a);
}
Point operator /(db a){
return Point(x/a,y/a);
}
db len2(){ //长度平方
return sqr(x)+sqr(y);
}
db len(){ //长度
return Sqrt(len2());
}
db polar(){ //向量的极角
return atan2(y,x); //返回与x轴正向夹角(-pi~pi]
}
}; inline db cross(Point a,Point b){ //叉积
return a.x*b.y-a.y*b.x;
} inline db dot(Point a,Point b){ //点积
return a.x*b.x+a.y*b.y;
} inline db dis(Point a,Point b){ //两点的距离
Point p=b-a; return p.len();
} Point centre_of_polygon(Point *p,int n){ //三角形重心加面积权值的平均求多边形的重心
db sum=,sumx=,sumy=;
Point p1=p[],p2=p[],p3;
for(int i=;i<n;i++){
p3=p[i];
db area=cross(p2-p1,p3-p2)/;
sum+=area;
sumx+=(p1.x+p2.x+p3.x)*area;
sumy+=(p1.y+p2.y+p3.y)*area;
p2=p3;
}
return Point(sumx/(*sum),sumy/(*sum));
} Point tmp[MAXN],ins[MAXN]; int convex_hull(Point *p,int n,Point *ch){ //求凸包
int m=;
sort(p,p+n);
for(int i=;i<n;i++){
while(m>&&dcmp(cross(tmp[m-]-tmp[m-],p[i]-tmp[m-]))<) m--;
tmp[m++]=p[i];
}
int k=m;
for(int i=n-;i>=;i--){
while(m>k&&dcmp(cross(tmp[m-]-tmp[m-],p[i]-tmp[m-]))<) m--;
tmp[m++]=p[i];
}
if(n>) m--;
for(int i=;i<m;i++) ch[i]=tmp[i];
return m;
} db ans;
pair<db,int>rec[MAXN];
Point point[MAXN],convex[MAXN],o;
vector<Point>side[MAXN],in[MAXN],st; bool cmp(Point a,Point b){
db dx=(a-o).polar(),dy=(b-o).polar();
if(dcmp(dx-dy)==) return dis(a,o)>dis(b,o);
return dx<dy;
} int main(void){
int n,m; scanf("%d",&n);
for(int i=;i<n;i++) point[i].input(); m=convex_hull(point,n,convex);
o=centre_of_polygon(convex,m); sort(point,point+n,cmp);
sort(convex,convex+m,cmp); for(int i=;i<n;i++){
point[i].ang=(point[i]-o).polar();
point[i+n]=point[i];
point[i+n].ang+=*pi;
}
for(int i=;i<m;i++){
convex[i].ang=(convex[i]-o).polar();
convex[i+m]=convex[i];
convex[i+m].ang+=*pi;
} for(int i=,j=;i<m;i++){
while(dcmp(convex[i].ang-point[j].ang)>) j++;
while(dcmp(point[j].ang-convex[i+].ang)<){
if(point[j]!=convex[i]) side[i].pb(point[j]);
j++;
}
} // a point on convex
for(int i=;i<m;i++){
int l=(i==? m-: i-),p=;
tmp[p++]=convex[l];
for(int j=;j<side[l].size();j++){
while(p>&&dcmp(cross(tmp[p-]-tmp[p-],side[l][j]-tmp[p-]))<) p--;
tmp[p++]=side[l][j];
}
for(int j=;j<side[i].size();j++){
while(p>&&dcmp(cross(tmp[p-]-tmp[p-],side[i][j]-tmp[p-]))<) p--;
tmp[p++]=side[i][j];
}
while(p>&&dcmp(cross(tmp[p-]-tmp[p-],convex[i+]-tmp[p-]))<) p--;
tmp[p++]=convex[i+]; db sum=dis(convex[l],convex[i])+dis(convex[i],convex[i+]);
for(int j=;j<p-;j++) sum-=dis(tmp[j],tmp[j+]);
rec[i]=MP(sum,i);
}
sort(rec,rec+m,greater<pair<db,int> >());
if(abs(rec[].se-rec[].se)!=&&abs(rec[].se-rec[].se)!=m-) ans=max(ans,rec[].fi+rec[].fi);
if(abs(rec[].se-rec[].se)!=&&abs(rec[].se-rec[].se)!=m-) ans=max(ans,rec[].fi+rec[].fi);
if(abs(rec[].se-rec[].se)!=&&abs(rec[].se-rec[].se)!=m-) ans=max(ans,rec[].fi+rec[].fi); // two consecutive point on convex
for(int i=;i<m;i++){
int l=(i==? m-: i-),p=;
tmp[p++]=convex[l];
for(int j=;j<side[l].size();j++){
while(p>&&dcmp(cross(tmp[p-]-tmp[p-],side[l][j]-tmp[p-]))<) p--;
tmp[p++]=side[l][j];
}
for(int j=;j<side[i].size();j++){
while(p>&&dcmp(cross(tmp[p-]-tmp[p-],side[i][j]-tmp[p-]))<) p--;
tmp[p++]=side[i][j];
}
for(int j=;j<side[(i+)%m].size();j++){
while(p>&&dcmp(cross(tmp[p-]-tmp[p-],side[(i+)%m][j]-tmp[p-]))<) p--;
tmp[p++]=side[(i+)%m][j];
}
while(p>&&dcmp(cross(tmp[p-]-tmp[p-],convex[i+]-tmp[p-]))<) p--;
tmp[p++]=convex[i+]; db sum=dis(convex[l],convex[i])+dis(convex[i],convex[i+])+dis(convex[i+],convex[i+]);
for(int j=;j<p-;j++) sum-=dis(tmp[j],tmp[j+]);
ans=max(ans,sum);
} // a point on convex and a point inside convex
for(int i=;i<m;i++){
int l=(i==? m-: i-),p=;
tmp[p++]=convex[l];
if(i==) tmp[p-].ang-=*pi;
for(int j=;j<side[l].size();j++){
st.pb(side[l][j]);
if(i==) st.back().ang-=*pi;
while(p>&&dcmp(cross(tmp[p-]-tmp[p-],side[l][j]-tmp[p-]))<) p--;
tmp[p++]=side[l][j];
}
for(int j=;j<side[i].size();j++){
st.pb(side[i][j]);
while(p>&&dcmp(cross(tmp[p-]-tmp[p-],side[i][j]-tmp[p-]))<) p--;
tmp[p++]=side[i][j];
}
while(p>&&dcmp(cross(tmp[p-]-tmp[p-],convex[i+]-tmp[p-]))<) p--;
tmp[p++]=convex[i+]; for(int j=,k=;j<p-;j++){
while(k<st.size()&&dcmp(tmp[j].ang-st[k].ang)>) k++;
while(k<st.size()&&dcmp(st[k].ang-tmp[j+].ang)<){
if(tmp[j]!=st[k]) in[j].pb(st[k]);
k++;
}
}
db sum=dis(convex[l],convex[i])+dis(convex[i],convex[i+]);
for(int j=;j<p-;j++) sum-=dis(tmp[j],tmp[j+]);
for(int j=;j<p-;j++){
int t=;
ins[t++]=tmp[j-];
for(int k=;k<in[j-].size();k++){
while(t>&&dcmp(cross(ins[t-]-ins[t-],in[j-][k]-ins[t-]))<) t--;
ins[t++]=in[j-][k];
}
for(int k=;k<in[j].size();k++){
while(t>&&dcmp(cross(ins[t-]-ins[t-],in[j][k]-ins[t-]))<) t--;
ins[t++]=in[j][k];
}
while(t>&&dcmp(cross(ins[t-]-ins[t-],tmp[j+]-ins[t-]))<) t--;
ins[t++]=tmp[j+]; db now=sum+dis(tmp[j-],tmp[j])+dis(tmp[j],tmp[j+]);
for(int k=;k<t-;k++) now-=dis(ins[k],ins[k+]);
ans=max(ans,now);
}
st.clear();
for(int j=;j<p;j++) in[j].clear();
}
printf("%.12f\n",(double)ans);
return ;
}

Gym 101986D Making Perimeter of the Convex Hull Shortest(凸包+极角排序)的更多相关文章

  1. 2018牛客网暑假ACM多校训练赛(第三场)I Expected Size of Random Convex Hull 计算几何,凸包,其他

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round3-I.html 题目传送门 - 2018牛客多校赛第三场 I ...

  2. convex hull

    1 什么是convex hull 就是凸包,是计算几何中的一个概念,计算几何是计算机图形学的基础之一. 对于二维平面来说是这样的:对于二维平面上的点集,凸包是位于最外层的点构成的包围其它所有的点的凸多 ...

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

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

  4. Convex Hull 实现理论+自制Python代码

    Convex Hull 概述 计算n维欧式空间散点集的凸包,有很多的方法.但是如果要实现快速运算则其难点在于:如何快速判断散点集的成员是否是在凸集的内部.如果可以简化判断的运算过程,则可以极大简化迭代 ...

  5. OpenCV入门之寻找图像的凸包(convex hull)

    介绍   凸包(Convex Hull)是一个计算几何(图形学)中的概念,它的严格的数学定义为:在一个向量空间V中,对于给定集合X,所有包含X的凸集的交集S被称为X的凸包.   在图像处理过程中,我们 ...

  6. 2D Convex Hulls and Extreme Points( Convex Hull Algorithms) CGAL 4.13 -User Manual

    1 Introduction A subset S⊆R2 is convex if for any two points p and q in the set the line segment wit ...

  7. Monotone Chain Convex Hull(单调链凸包)

    Monotone Chain Convex Hull(单调链凸包)算法伪代码: //输入:一个在平面上的点集P //点集 P 按 先x后y 的递增排序 //m 表示共a[i=0...m]个点,ans为 ...

  8. opencv::凸包-Convex Hull

    概念介绍 什么是凸包(Convex Hull),在一个多变形边缘或者内部任意两个点的连线都包含在多边形边界或者内部. 正式定义:包含点集合S中所有点的最小凸多边形称为凸包 Graham扫描算法 首先选 ...

  9. Convex Hull | Set 1

    Given a set of points in the plane. the convex hull of the set is the smallest convex polygon that c ...

随机推荐

  1. maven打包指定main入口插件

    <!--打包插件 --><plugin> <groupId>org.apache.maven.plugins</groupId> <artifac ...

  2. 使用jquery给html标签加点击事件

    //直接给所有img标签绑定click事件 $("img").click(function(){ alert('你点击了图片'); }) //使用bind方法绑定click事件 $ ...

  3. React native 之 async/await

    参考资料 :https://www.jianshu.com/p/1e75bd387aa0 要点: 1. async function(){} 将普通函数转换成Promise 2. await 表达式/ ...

  4. #381 Div2 Problem C Alyona and mex (思维 && 构造)

    题意 : 题目的要求是构造出一个长度为 n 的数列, 构造条件是在接下来给出的 m 个子区间中, 要求每一个子区间的mex值最大, 然后在这 m 个子区间产生的mex值中取最小的输出, 并且输出构造出 ...

  5. Introduction-to-Psychology Slides

    最近在网易公开课学习耶鲁大学Paul Bloom教授的<心理学导论>,英文水平有限,视频中一直没有出现PPT,无意中找到一份课件,现分享于此,大家自取! 链接:https://pan.ba ...

  6. pythonCSV模块

    在爬虫过后会取得很多信息! 将信息存起来方法还很多中!今天提一下CSV模块 导入模块 import csv 这里先写个列表 rows = [['zhangsan',20],['lisi',22],[' ...

  7. 响应式布局@media screen and ( max-width: 像素值 ) {}

    设计思路很简单,首先先定义在标准浏览器下的固定宽度(假如标准浏览器的分辨率为1024px,那么我们设置宽为980px),然后用Media Query来监测浏览器的尺寸变化,当浏览器的分辨率小于1024 ...

  8. [CSP-S模拟测试]:bird(线段树优化DP)

    题目传送门(内部题89) 输入格式 第一行两个数$n$和$k$,分别表示小鸟的只数和$R$装弹时间.接下来$n$行,每行两个数$l,r$表示$n$只小鸟初始时的头和尾的$x$坐标. 输出格式 输出一个 ...

  9. Hashtable 和 HashMap 的区别是:

    HashMap 是内部基于哈希表实现,该类继承AbstractMap,实现Map接口 Hashtable 线程安全的,而 HashMap 是线程不安全的 Properties 类 继承了 Hashta ...

  10. CDH安装时,部分节点不受管控

    解决方案: /opt/cm-5.12.0/etc/init.d/cloudera-scm-agent stop cd /opt/cm-5.12.0/lib/cloudera-scm-agent/ rm ...