Gym 101986D Making Perimeter of the Convex Hull Shortest(凸包+极角排序)
首先肯定是构造一个完整的凸包包括所有的点,那么要使得刚好有两个点在外面,满足这个条件的只有三种情况。
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(凸包+极角排序)的更多相关文章
- 2018牛客网暑假ACM多校训练赛(第三场)I Expected Size of Random Convex Hull 计算几何,凸包,其他
原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round3-I.html 题目传送门 - 2018牛客多校赛第三场 I ...
- convex hull
1 什么是convex hull 就是凸包,是计算几何中的一个概念,计算几何是计算机图形学的基础之一. 对于二维平面来说是这样的:对于二维平面上的点集,凸包是位于最外层的点构成的包围其它所有的点的凸多 ...
- 凸包(Convex Hull)构造算法——Graham扫描法
凸包(Convex Hull) 在图形学中,凸包是一个非常重要的概念.简明的说,在平面中给出N个点,找出一个由其中某些点作为顶点组成的凸多边形,恰好能围住所有的N个点. 这十分像是在一块木板上钉了N个 ...
- Convex Hull 实现理论+自制Python代码
Convex Hull 概述 计算n维欧式空间散点集的凸包,有很多的方法.但是如果要实现快速运算则其难点在于:如何快速判断散点集的成员是否是在凸集的内部.如果可以简化判断的运算过程,则可以极大简化迭代 ...
- OpenCV入门之寻找图像的凸包(convex hull)
介绍 凸包(Convex Hull)是一个计算几何(图形学)中的概念,它的严格的数学定义为:在一个向量空间V中,对于给定集合X,所有包含X的凸集的交集S被称为X的凸包. 在图像处理过程中,我们 ...
- 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 ...
- Monotone Chain Convex Hull(单调链凸包)
Monotone Chain Convex Hull(单调链凸包)算法伪代码: //输入:一个在平面上的点集P //点集 P 按 先x后y 的递增排序 //m 表示共a[i=0...m]个点,ans为 ...
- opencv::凸包-Convex Hull
概念介绍 什么是凸包(Convex Hull),在一个多变形边缘或者内部任意两个点的连线都包含在多边形边界或者内部. 正式定义:包含点集合S中所有点的最小凸多边形称为凸包 Graham扫描算法 首先选 ...
- 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 ...
随机推荐
- 获取当前国家与ip地址
JS获取当前国家示例: <script src="http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js"& ...
- 记ubuntu sudo无法使用,su密码不对的解决办法
前言 因为我有强制关机的习惯, 然后就杯具了.. ubuntu版本是 16.04 sudo没法使用, su密码不对, 顿时我就慌了 解决方案 1.1.开机点击ESC,进去GUN GRUB界面 1.2. ...
- 【BZOJ3931】[CQOI2015]网络吞吐量
Description 路由是指通过计算机网络把信息从源地址传输到目的地址的活动,也是计算机网络设计中的重点和难点.网络中实现路由转发的硬件设备称为路由器.为了使数据包最快的到达目的地,路由器需要选择 ...
- [BZOJ3033]:太鼓达人(爆搜)
题目传送门 题目描述 七夕祭上,Vani牵着cl的手,在明亮的灯光和欢乐的气氛中愉快地穿行.这时,在前面忽然出现了一台太鼓达人机台,而在机台前坐着的是刚刚被精英队伍成员XLk.Poet_shy和lyd ...
- the path component: '/var' is world-writable
java.io.IOException: the path component: '/var' is world-writable. Its permissions are 0666. Pleas ...
- linux grep 正则
grep : 显示匹配行 -v: 反显示 -e 使用扩展正则表达式 黑色字体表明是原生正则表达式 红色字体表明是扩张正则表达式 1.匹配操作符 \: 转义字符串(正则使用扩展字符操作 没有使用-e ...
- 使用Zabbix通过ILO管理口监控惠普服务器
https://blog.csdn.net/qq_41571056/article/details/82928542
- 一、基础篇--1.1Java基础-int 和 Integer 有什么区别,Integer的值缓存范围
int和Integer的区别 int是基本数据类型,Integer是int的包装类. Integer必须实例化后才能使用,int变量不需要. Integer实际是对象的引用,生成一个新对象实际上是生成 ...
- tensorflow基本操作(1)
import tensorflow as tf import numpy as np 点乘,支持broadcasting 乘号* 和 multiply等价 mul已经废弃不用了 matmul 是矩阵相 ...
- leetcode-mid-sorting and searching - 240. Search a 2D Matrix II -NO
mycode time limited def searchMatrix(matrix, target): def deal(data): if not data: return False ro ...