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

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. 自己用ul模拟实现下拉多选框,

    模拟实现下拉多选框 效果如下 <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...

  2. AQS源码分析笔记

    经过昨晚的培训.对AQS源码的理解有所加强,现在写个小笔记记录一下 同样,还是先写个测试代码,debug走一遍流程, 然后再总结一番即可. 测试代码 import java.util.concurre ...

  3. CF1242C. Sum Balance

    题目描述 k组数,每组ni个,数互不相同 把每组数中的一个移到其他组(或者不移动),使得最终每组数的个数不变且总和相等 k<=15,ni<=5000 题解 最终的移动关系一定为若干个环 枚 ...

  4. BZOJ 3398: [Usaco2009 Feb]Bullcow 牡牛和牝牛 水题~

    水~ #include <cstdio> #define N 100004 #define mod 5000011 #define setIO(s) freopen(s".in& ...

  5. 2018百度之星初赛B轮 p1m2

    p1m2 Accepts: 954 Submissions: 4063 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/1310 ...

  6. luogu P1077 摆花 x

    P1077 摆花 题目描述 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆.通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号.为了在门口展出更多种花,规定第i种花不能 ...

  7. cocos2d 15款游戏源码

    https://blog.csdn.net/jailman/article/details/78678972

  8. Tarjan算法初步

    一.前置知识: 强连通分量:有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(stron ...

  9. 20165220课程设计个人报告——Part4-Cortex M4模块

    个人报告: 20165220 葛宇豪 1.个人贡献 a.实验环境搭建 b.代码分析与理解 2.设计中遇到的问题以及解决方案 问题1:mdk5每次编译之前都会直接闪退 刚开始以为是环境问题,后来上网查资 ...

  10. http://www.malware-traffic-analysis.net/2018/index.html

    http://www.malware-traffic-analysis.net/2018/index.html