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 }
posted @ 2019-10-04 15:18  DD_BOND  阅读(315)  评论(0编辑  收藏  举报