Gym 101986D Making Perimeter of the Convex Hull Shortest(凸包+极角排序)

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

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

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

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

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

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

k点为重心

  1 //      ——By DD_BOND
  2
  3 //#include<bits/stdc++.h>
  4 //#include<unordered_map>
  5 //#include<unordered_set>
  6 #include<functional>
  7 #include<algorithm>
  8 #include<iostream>
  9 //#include<ext/rope>
 10 #include<iomanip>
 11 #include<climits>
 12 #include<cstring>
 13 #include<cstdlib>
 14 #include<cstddef>
 15 #include<cstdio>
 16 #include<memory>
 17 #include<vector>
 18 #include<cctype>
 19 #include<string>
 20 #include<cmath>
 21 #include<queue>
 22 #include<deque>
 23 #include<ctime>
 24 #include<stack>
 25 #include<map>
 26 #include<set>
 27
 28 #define fi first
 29 #define se second
 30 #define pb push_back
 31 #define MP make_pair
 32
 33 #pragma GCC optimize(3)
 34 #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
 35
 36 using namespace std;
 37
 38 typedef long double db;
 39 typedef long long ll;
 40 typedef pair<db,db> Pd;
 41 typedef pair<int,int> P;
 42 typedef pair<ll,ll> Pll;
 43
 44 const db eps=1e-8;
 45 const int MAXN=1e6+10;
 46 const db pi=acos(-1.0);
 47 const ll INF=0x3f3f3f3f3f3f3f3f;
 48
 49 inline int dcmp(db x){
 50     if(fabs(x)<eps) return 0;
 51     return (x>0? 1: -1);
 52 }
 53
 54 inline db Sqrt(db x){
 55     return x>0? sqrt(x): 0;
 56 }
 57
 58 inline db sqr(db x){ return x*x; }
 59
 60 struct Point{
 61     db x,y,ang;
 62     Point(){ x=0,y=0; }
 63     Point(db _x,db _y):x(_x),y(_y){}
 64     void input(){
 65         double _x,_y;
 66         scanf("%lf%lf",&_x,&_y);
 67         x=_x,y=_y;
 68     }
 69     bool operator ==(const Point &b)const{
 70         return (dcmp(x-b.x)==0&&dcmp(y-b.y)==0);
 71     }
 72     bool operator !=(const Point &b)const{
 73         return !((dcmp(x-b.x)==0&&dcmp(y-b.y)==0));
 74     }
 75     bool operator <(const Point &b)const{
 76         return (dcmp(x-b.x)==0? dcmp(y-b.y)<0 : x<b.x);
 77     }
 78     Point operator +(const Point &b)const{
 79         return Point(x+b.x,y+b.y);
 80     }
 81     Point operator -(const Point &b)const{
 82         return Point(x-b.x,y-b.y);
 83     }
 84     Point operator *(db a){
 85         return Point(x*a,y*a);
 86     }
 87     Point operator /(db a){
 88         return Point(x/a,y/a);
 89     }
 90     db len2(){  //长度平方
 91         return sqr(x)+sqr(y);
 92     }
 93     db len(){   //长度
 94         return Sqrt(len2());
 95     }
 96     db polar(){ //向量的极角
 97         return atan2(y,x);   //返回与x轴正向夹角(-pi~pi]
 98     }
 99 };
100
101 inline db cross(Point a,Point b){   //叉积
102     return a.x*b.y-a.y*b.x;
103 }
104
105 inline db dot(Point a,Point b){ //点积
106     return a.x*b.x+a.y*b.y;
107 }
108
109 inline db dis(Point a,Point b){ //两点的距离
110     Point p=b-a;    return p.len();
111 }
112
113 Point centre_of_polygon(Point *p,int n){    //三角形重心加面积权值的平均求多边形的重心
114     db sum=0,sumx=0,sumy=0;
115     Point p1=p[0],p2=p[1],p3;
116     for(int i=2;i<n;i++){
117         p3=p[i];
118         db area=cross(p2-p1,p3-p2)/2;
119         sum+=area;
120         sumx+=(p1.x+p2.x+p3.x)*area;
121         sumy+=(p1.y+p2.y+p3.y)*area;
122         p2=p3;
123     }
124     return Point(sumx/(3*sum),sumy/(3*sum));
125 }
126
127 Point tmp[MAXN],ins[MAXN];
128
129 int convex_hull(Point *p,int n,Point *ch){  //求凸包
130     int m=0;
131     sort(p,p+n);
132     for(int i=0;i<n;i++){
133         while(m>1&&dcmp(cross(tmp[m-1]-tmp[m-2],p[i]-tmp[m-1]))<0) m--;
134         tmp[m++]=p[i];
135     }
136     int k=m;
137     for(int i=n-2;i>=0;i--){
138         while(m>k&&dcmp(cross(tmp[m-1]-tmp[m-2],p[i]-tmp[m-1]))<0) m--;
139         tmp[m++]=p[i];
140     }
141     if(n>1) m--;
142     for(int i=0;i<m;i++)    ch[i]=tmp[i];
143     return m;
144 }
145
146 db ans;
147 pair<db,int>rec[MAXN];
148 Point point[MAXN],convex[MAXN],o;
149 vector<Point>side[MAXN],in[MAXN],st;
150
151 bool cmp(Point a,Point b){
152     db dx=(a-o).polar(),dy=(b-o).polar();
153     if(dcmp(dx-dy)==0)  return dis(a,o)>dis(b,o);
154     return dx<dy;
155 }
156
157 int main(void){
158     int n,m;  scanf("%d",&n);
159     for(int i=0;i<n;i++)    point[i].input();
160
161     m=convex_hull(point,n,convex);
162     o=centre_of_polygon(convex,m);
163
164     sort(point,point+n,cmp);
165     sort(convex,convex+m,cmp);
166
167     for(int i=0;i<n;i++){
168         point[i].ang=(point[i]-o).polar();
169         point[i+n]=point[i];
170         point[i+n].ang+=2*pi;
171     }
172     for(int i=0;i<m;i++){
173         convex[i].ang=(convex[i]-o).polar();
174         convex[i+m]=convex[i];
175         convex[i+m].ang+=2*pi;
176     }
177
178     for(int i=0,j=0;i<m;i++){
179         while(dcmp(convex[i].ang-point[j].ang)>0)   j++;
180         while(dcmp(point[j].ang-convex[i+1].ang)<0){
181             if(point[j]!=convex[i]) side[i].pb(point[j]);
182             j++;
183         }
184     }
185
186     // a point on convex
187     for(int i=0;i<m;i++){
188         int l=(i==0? m-1: i-1),p=0;
189         tmp[p++]=convex[l];
190         for(int j=0;j<side[l].size();j++){
191             while(p>1&&dcmp(cross(tmp[p-1]-tmp[p-2],side[l][j]-tmp[p-1]))<0)    p--;
192             tmp[p++]=side[l][j];
193         }
194         for(int j=0;j<side[i].size();j++){
195             while(p>1&&dcmp(cross(tmp[p-1]-tmp[p-2],side[i][j]-tmp[p-1]))<0)    p--;
196             tmp[p++]=side[i][j];
197         }
198         while(p>1&&dcmp(cross(tmp[p-1]-tmp[p-2],convex[i+1]-tmp[p-1]))<0)    p--;
199         tmp[p++]=convex[i+1];
200
201         db sum=dis(convex[l],convex[i])+dis(convex[i],convex[i+1]);
202         for(int j=0;j<p-1;j++)  sum-=dis(tmp[j],tmp[j+1]);
203         rec[i]=MP(sum,i);
204     }
205     sort(rec,rec+m,greater<pair<db,int> >());
206     if(abs(rec[0].se-rec[1].se)!=1&&abs(rec[0].se-rec[1].se)!=m-1)  ans=max(ans,rec[0].fi+rec[1].fi);
207     if(abs(rec[0].se-rec[2].se)!=1&&abs(rec[0].se-rec[2].se)!=m-1)  ans=max(ans,rec[0].fi+rec[2].fi);
208     if(abs(rec[1].se-rec[2].se)!=1&&abs(rec[1].se-rec[2].se)!=m-1)  ans=max(ans,rec[1].fi+rec[2].fi);
209
210     // two consecutive point on convex
211     for(int i=0;i<m;i++){
212         int l=(i==0? m-1: i-1),p=0;
213         tmp[p++]=convex[l];
214         for(int j=0;j<side[l].size();j++){
215             while(p>1&&dcmp(cross(tmp[p-1]-tmp[p-2],side[l][j]-tmp[p-1]))<0)    p--;
216             tmp[p++]=side[l][j];
217         }
218         for(int j=0;j<side[i].size();j++){
219             while(p>1&&dcmp(cross(tmp[p-1]-tmp[p-2],side[i][j]-tmp[p-1]))<0)    p--;
220             tmp[p++]=side[i][j];
221         }
222         for(int j=0;j<side[(i+1)%m].size();j++){
223             while(p>1&&dcmp(cross(tmp[p-1]-tmp[p-2],side[(i+1)%m][j]-tmp[p-1]))<0)    p--;
224             tmp[p++]=side[(i+1)%m][j];
225         }
226         while(p>1&&dcmp(cross(tmp[p-1]-tmp[p-2],convex[i+2]-tmp[p-1]))<0)    p--;
227         tmp[p++]=convex[i+2];
228
229         db sum=dis(convex[l],convex[i])+dis(convex[i],convex[i+1])+dis(convex[i+1],convex[i+2]);
230         for(int j=0;j<p-1;j++)  sum-=dis(tmp[j],tmp[j+1]);
231         ans=max(ans,sum);
232     }
233
234     // a point on convex and a point inside convex
235     for(int i=0;i<m;i++){
236         int l=(i==0? m-1: i-1),p=0;
237         tmp[p++]=convex[l];
238         if(i==0)    tmp[p-1].ang-=2*pi;
239         for(int j=0;j<side[l].size();j++){
240             st.pb(side[l][j]);
241             if(i==0)    st.back().ang-=2*pi;
242             while(p>1&&dcmp(cross(tmp[p-1]-tmp[p-2],side[l][j]-tmp[p-1]))<0)    p--;
243             tmp[p++]=side[l][j];
244         }
245         for(int j=0;j<side[i].size();j++){
246             st.pb(side[i][j]);
247             while(p>1&&dcmp(cross(tmp[p-1]-tmp[p-2],side[i][j]-tmp[p-1]))<0)    p--;
248             tmp[p++]=side[i][j];
249         }
250         while(p>1&&dcmp(cross(tmp[p-1]-tmp[p-2],convex[i+1]-tmp[p-1]))<0)    p--;
251         tmp[p++]=convex[i+1];
252
253         for(int j=0,k=0;j<p-1;j++){
254             while(k<st.size()&&dcmp(tmp[j].ang-st[k].ang)>0)   k++;
255             while(k<st.size()&&dcmp(st[k].ang-tmp[j+1].ang)<0){
256                 if(tmp[j]!=st[k])   in[j].pb(st[k]);
257                 k++;
258             }
259         }
260         db sum=dis(convex[l],convex[i])+dis(convex[i],convex[i+1]);
261         for(int j=0;j<p-1;j++)  sum-=dis(tmp[j],tmp[j+1]);
262         for(int j=1;j<p-1;j++){
263             int t=0;
264             ins[t++]=tmp[j-1];
265             for(int k=0;k<in[j-1].size();k++){
266                 while(t>1&&dcmp(cross(ins[t-1]-ins[t-2],in[j-1][k]-ins[t-1]))<0)    t--;
267                 ins[t++]=in[j-1][k];
268             }
269             for(int k=0;k<in[j].size();k++){
270                 while(t>1&&dcmp(cross(ins[t-1]-ins[t-2],in[j][k]-ins[t-1]))<0)  t--;
271                 ins[t++]=in[j][k];
272             }
273             while(t>1&&dcmp(cross(ins[t-1]-ins[t-2],tmp[j+1]-ins[t-1]))<0)  t--;
274             ins[t++]=tmp[j+1];
275
276             db now=sum+dis(tmp[j-1],tmp[j])+dis(tmp[j],tmp[j+1]);
277             for(int k=0;k<t-1;k++)  now-=dis(ins[k],ins[k+1]);
278             ans=max(ans,now);
279         }
280         st.clear();
281         for(int j=0;j<p;j++)    in[j].clear();
282     }
283     printf("%.12f\n",(double)ans);
284     return 0;
285 }

原文地址:https://www.cnblogs.com/dd-bond/p/11622216.html

时间: 2024-10-14 15:17:29

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

zoj 3871 Convex Hull(凸包)

题目链接:zoj 3871 Convex Hull 枚举每条边,计算出有多少情况下为凸包的边界,即有多少点在该边的左边. #include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <complex> #include <algorithm> using namespace std; typedef pair<int,int&g

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

凸包(Convex Hull) 在图形学中,凸包是一个非常重要的概念.简明的说,在平面中给出N个点,找出一个由其中某些点作为顶点组成的凸多边形,恰好能围住所有的N个点. 这十分像是在一块木板上钉了N个钉子,然后用一根绷紧的橡皮筋它们都圈起来,这根橡皮筋的形状就是所谓的凸包. 计算凸包的一个著名算法是Graham Scan法,它的时间复杂度与所采用的排序算法时间复杂度相同,通常采用线性对数算法,因此为\( O\left(N\mathrm{log}\left(N\right)\right) \).

OpenCV Tutorials &mdash;&mdash; Convex Hull

凸包 找到物体的轮廓之后,再找其凸包   void convexHull(InputArray points, OutputArray hull, bool clockwise=false, bool returnPoints=true ) Parameters: points – Input 2D point set, stored in std::vector or Mat. hull – Output convex hull. It is either an integer vector

opencv笔记(二十四)——得到轮廓之后找到凸包convex hull

当我们得到一张轮廓之后,我们可以对其运用convexHull方法,寻找该轮廓的凸包. 一个轮廓可以有无数个包围它的外壳,而其中表面积最小的一个外壳,就是凸包. void convexHull(InputArray points, OutputArray hull, bool clockwise=false, bool returnPoints=true ) points是一个contour. vector<Point>类型或者Mat类型 hull是输出,也是一个点集vector<Poin

Computational Geometry PA1 Convex Hull (凸包)

题目链接:http://dsa.cs.tsinghua.edu.cn/oj/problem.shtml?id=710 CG2015 PA1-1 Convex Hull (凸包) Description (描述) After learning Chapter 1, you must have mastered the convex hull very well. Yes, convex hull is at the kernel of computational geometry and serv

Monotone Chain Convex Hull(单调链凸包)

1 Monotone Chain Convex Hull(单调链凸包)算法伪代码: 2 //输入:一个在平面上的点集P 3 //点集 P 按 先x后y 的递增排序 4 //m 表示共a[i=0...m]个点,ans为要求的点; 5 struct P 6 { 7 int x,y; 8 friend int operator < (P a, P b) 9 { 10 if((a.x<b.x) || (a.x==b.x && a.y<b.y)) 11 return 1; 12 r

convex hull - Graham&#39;s scam Algorithm version-0.1

input:a finite set of two dimentional points P (the number of points n is more than 2) output: the convex hull of P Pesudo: 1, sort P in Lexgrahical order 2, construct the upper hull UHLL: 1' add two points on UHLL 2' for i=3 to  n add P[i] on UHLL W

凸包问题Finding the convex hull

问题描述:找到包含点集Q的最小凸多边形.使得点集内的点均在凸多边形的边上或内部. 即集合内任意两点的连线均在凸多边形内部. 输入:平面上的n个点的集合Q 输出: CH(Q):Q的convexhull (一)蛮力法思路: 找到点集内的内部点去掉,剩余未边界点. 内部点的判断:只要其中三点A,B,C构成的三角形包含的点P则P为内部点. 三角形内部点具体判断方法: 如果P在△ABC内部,则A,P两个点在BC同侧:P,B两个点在AC同侧:C,P两个点在AB同侧.转换为点与线关系的判断. 判断点P与直线A

Convex Hull | Set 1

Given a set of points in the plane. the convex hull of the set is the smallest convex polygon that contains all the points of it. https://www.geeksforgeeks.org/convex-hull-set-1-jarviss-algorithm-or-wrapping/ Lin家 Java: // Java program to find convex