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

Posted dd-bond

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 

以上是关于Gym 101986D Making Perimeter of the Convex Hull Shortest(凸包+极角排序)的主要内容,如果未能解决你的问题,请参考以下文章

Go语言入门——interface

Making User-Managed Backups-17.4Making User-Managed Backups of Online Tablespaces and Datafiles(示例代

3 Mental Habits Making You Miserable

Survey of Automated Market Making Algorithms

Making Money

Market Making is simpler than you think!