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

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. electron 点击事件无效

    用CSS的 -webkit-app-region: drag;设置窗口可以移动后,点击事件无效 解决办法暂时不知道, 给点击的按钮加 -webkit-app-region: no-drag; 就可以点 ...

  2. electron监听系统托盘,electron是否最小化到系统托盘

    在项目中需要判断窗口是否最小化在系统托盘上,任务栏那已经关闭,查了一晚上的api,始终找不到可以调用的方法,最后绞尽脑汁想到了一个办法,那就是在点右上角的关闭按钮时,加个全局变量,用来标识已经最小到系 ...

  3. html address标签 语法

    html address标签 语法 作用:定义文档作者/所有者的联系信息. 说明:如果 <address> 元素位于 <body> 元素内部,则它表示该文档作者/所有者的联系信 ...

  4. Django之nginx+wsgi后台部署(最新版)

    0-部署准备 1.要使用安全组打开腾讯云的80端口 腾讯云的80端口不能访问​www.jianshu.com 以实际项目部署为例 项目名称api_learn: Python版本:python 3.6. ...

  5. HDU2196computer

    就是求每个点为起始点的最长链的长度. 写一下各个数组的意思吧. f[i][0]为点i向下走最长的距离:f[i][1]为点i向下走第二长的距离: xia[i][0]为点i向下走最长距离所要走的儿子节点: ...

  6. HDU 1097 快速幂

    #include<iostream> using namespace std; long long quick(long long a,long long b,int c) { ; a=a ...

  7. K8S简介

    简介 Kubernetes是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规 ...

  8. python安装报错error writing to file:......

    今天换了win10 64电脑,安装python3.6.8时,报错:error writing to file:...... 安装时,右键--以管理员身份运行,安装成功.

  9. scrapy项目1:爬取某培训机构老师信息(spider类)

    1.scrapy爬虫的流程,可简单该括为以下4步: 1).新建项目---->scrapy startproject 项目名称(例如:myspider) >>scrapy.cfg为项目 ...

  10. 数据科学20个最好的Python库

    Python 在解决数据科学任务和挑战方面继续处于领先地位.去年,我们曾发表一篇博客文章 Top 15 Python Libraries for Data Science in 2017,概述了当时业 ...