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

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. 【NOIP2016提高A组模拟8.17】(雅礼联考day1)Binary

    题目 分析 首先每个数对\(2^i\)取模.也就是把每个数的第i位以后删去. 把它们放进树状数组里面. 那么当查询操作, 答案就位于区间\([2^i-x,2^{i-1}-1-x]\)中,直接查询就可以 ...

  2. 14.django返回展示一张图片

    urlpatterns = [ path('admin/', admin.site.urls), # 使用django返回一张土图片的时候需要间接的访问一个中间接口,是html页面的中的img的src ...

  3. docker-compose命令及yaml文件

    Docker-compose常用命令 docker-compose up -d nginx 构建建启动nignx容器 docker-compose exec nginx bash 登录到nginx容器 ...

  4. 判断字符串a是否以字符串b开头或结尾

    使用字符串的 str.startwith() 和 str.endswith()方法 import os , stat for name in os.listdir('.') if name.endsw ...

  5. jsp页面实现上传文件,并且还得支持断点续传的功能

    我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用. 首先我们需要了解的是上传文件三要素: 1.表单提交方式:post (get方式提交有大小 ...

  6. (59)Linux操作系统深入应用

    目录: 第一部分:嵌入式的含义 第二部分:DOS命令 第三部分:linux的发展历史(与unix的关系) 第四部分: 基于ubuntu下的linux命令详解大全         第一部分:嵌入式的含义 ...

  7. Qt数据库之数据库连接池

     前面的章节里,我们使用了下面的函数创建和取得数据库连接: void createConnectionByName(const QString &connectionName) { QSql ...

  8. leetcode-mid-others-169. Majority Element¶

    mycode  54.93% class Solution(object): def majorityElement(self, nums): """ :type num ...

  9. acl权限设置

    acl权限分配 1.setfacl设置文件或目录的权限 setfacl -m u:user:rw text setfacl -m user:rwx /mnt 2.getfacl查看文件或目录的权限 g ...

  10. 用Vue来实现音乐播放器(二十三):音乐列表

    当我们将音乐列表往上滑的时候   我们上面的歌手图片部分也会变小 当我们将音乐列表向下拉的时候   我们的图片会放大 当我们将音乐列表向上滑的时候   我们的图片有一个高斯模糊的效果 并且随着我们的列 ...