POJ 3743 LL’s cake(圆+PSLG)

Posted dd-bond

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 3743 LL’s cake(圆+PSLG)相关的知识,希望对你有一定的参考价值。

题意是给你一块在原点半径为10的圆,然后告诉你一条直线在圆弧上的极角,相当于用这条直线把这个圆分成两半,然后一共是n条直线切圆,就好比切蛋糕,问你其中最大一块的面积是多少。

如果我们将圆弧转化成直线边,那么这个题就变成PSLG裸题,但是这里是圆弧,所以我们需要将其转化。

我先将所有在圆上的点记录下来,最后极角排序,绕一周,这些点分割出来肯定会有一部分算面积的时候是要算上那部分弓型面积,但是有一部分不是,主要是这部分面积仅仅就是这块弓型面积,没有其他多边形面积,例如样例3,为了避免这种问题,我们可以直接在相邻两点之间塞入一个点,在进行连边,那么相当于我们给仅仅只有弓型区域内的点一个三角形面积,这样主要保证的是在跑PSLG的时候可以把这块面积算进去,因为每条边只算两次,但是如果是仅仅只有弓型面积所在的那条边,本来应该逆时针绕一圈算面积,所以这样就会有问题。

C++提交正确 G++wa惨???

这样就会有问题

技术图片

 

 

这样建边就没有大问题了

技术图片

 

 

  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 using namespace std;
 34 
 35 typedef double db;
 36 typedef long long ll;
 37 typedef pair<db,db> Pd;
 38 typedef pair<int,int> P;
 39 typedef pair<ll,ll> Pll;
 40 
 41 const db eps=1e-8;
 42 const int MAXN=1e5+10;
 43 const db pi=acos(-1.0);
 44 const ll INF=0x3f3f3f3f3f3f3f3f;
 45 
 46 inline int dcmp(db x)
 47     if(fabs(x)<eps) return 0;
 48     return (x>0? 1: -1);
 49 
 50 
 51 inline db Sqrt(db x)
 52     return x>0? sqrt(x): 0;
 53 
 54 
 55 inline db sqr(db x) return x*x; 
 56 
 57 struct Point
 58     db x,y; int id,nx;
 59     Point() x=0,y=0; 
 60     Point(db _x,db _y):x(_x),y(_y)
 61     void input()
 62         double _x,_y;
 63         scanf("%lf%lf",&_x,&_y);
 64         x=_x,y=_y;
 65     
 66     void output() printf("%.4f %.4f\\n",(double)x,(double)y); 
 67     bool operator ==(const Point &b)const
 68         return (dcmp(x-b.x)==0&&dcmp(y-b.y)==0);
 69     
 70     bool operator !=(const Point &b)const
 71         return !((dcmp(x-b.x)==0&&dcmp(y-b.y)==0));
 72     
 73     bool operator <(const Point &b)const
 74         return (dcmp(x-b.x)==0? dcmp(y-b.y)<0 : x<b.x);
 75     
 76     db operator ^(const Point &b)const     //叉积
 77         return x*b.y-y*b.x;
 78     
 79     db operator *(const Point &b)const     //点积
 80         return x*b.x+y*b.y;
 81     
 82     Point operator +(const Point &b)const
 83         return Point(x+b.x,y+b.y);
 84     
 85     Point operator -(const Point &b)const
 86         return Point(x-b.x,y-b.y);
 87     
 88     Point operator *(db a)
 89         return Point(x*a,y*a);
 90     
 91     Point operator /(db a)
 92         return Point(x/a,y/a);
 93     
 94     db len2()  //长度平方
 95         return sqr(x)+sqr(y);
 96     
 97     db len()   //长度
 98         return Sqrt(len2());
 99     
100     db polar() //向量的极角
101         return atan2(y,x);   //返回与x轴正向夹角(-pi~pi]
102     
103     Point rotate_left()    //逆时针旋转90度
104         return Point(-y,x);
105     
106     Point rotate_right()   //顺时针旋转90度
107         return Point(y,-x);
108     
109     Point rotate(Point p,db ang)   //绕点p逆时针旋转ang度
110         Point v=(*this)-p;
111         db c=cos(ang),s=sin(ang);
112         return Point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c);
113     
114 ;
115 
116 inline db cross(Point a,Point b)   //叉积
117     return a.x*b.y-a.y*b.x;
118 
119 
120 inline db dot(Point a,Point b) //点积
121     return a.x*b.x+a.y*b.y;
122 
123 
124 inline db dis(Point a,Point b) //两点的距离
125     Point p=b-a;    return p.len();
126 
127 
128 inline db rad(Point a,Point b)    //两个向量的夹角
129     return fabs(atan2(fabs(cross(a,b)),dot(a,b)));
130 
131 
132 inline bool is_parallel(Point a,Point b)  //判断向量是否平行
133     db p=rad(a,b);
134     return dcmp(p)==0||dcmp(p-pi)==0;
135 
136 
137 struct Line
138     Point s,e;
139     Line()
140     Line(Point _s,Point _e):s(_s),e(_e) //两点确定直线
141     Point operator &(const Line &b)const    //求两直线交点
142         Point res=s;
143         db t=((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));
144         res.x+=(e.x-s.x)*t;
145         res.y+=(e.y-s.y)*t;
146         return res;
147     
148 ;
149 
150 inline int relation(Point p,Line l)   //点和向量关系   1:左侧   2:右侧   3:在线上
151     int c=dcmp(cross(p-l.s,l.e-l.s));
152     if(c<0) return 1;
153     else if(c>0)    return 2;
154     else    return 3;
155 
156 
157 inline bool is_parallel(Line a,Line b)    //直线平行
158     return is_parallel(a.e-a.s,b.e-b.s);
159 
160 
161 struct Circle
162     Point p;
163     db r;
164     Circle()
165     Circle(Point _p,db _r):p(_p),r(_r)
166 ;
167 
168 inline int relation(Point p,Circle a) //点和圆的位置关系  0:圆外    1:圆上   2:圆内
169     db d=dis(p,a.p);
170     if(dcmp(d-a.r)==0)  return 1;
171     return (dcmp(d-a.r)<0? 2: 0);
172 
173 
174 inline db area_radian(db th,db r) //返回半径为R,弧度为th的弓形面积
175     return 0.5*r*r*(th-sin(th));
176 
177 
178 inline db polygon_area(vector<Point> p)    //多边形的有向面积,加上绝对值就是面积  正值表示输入点按照逆时针 否则为顺时针
179     int n=p.size(); db area=0;
180     for(int i=1;i<n-1;i++)  area+=cross(p[i]-p[0],p[i+1]-p[0]);
181     area=fabs(area)/2;
182     for(int i=0,j=1;i<n;i++,j++)
183         if(j==n)    j=0;
184         if(p[i].nx==p[j].id||p[j].nx==p[i].id)  area+=area_radian(rad(p[i],p[j]),10);
185     
186     return area;
187 
188 
189 struct Edge
190     int from,to;
191     db ang;
192     Edge() ang=from=to=0; 
193     Edge(int s,int t,db a) from=s,to=t,ang=a; 
194 ;
195 int n,m,face_cnt;   //平面个数 包括外面最大的多边形
196 db area[MAXN];  //每个多边形面积
197 Point point[MAXN];  //平面内所有的点
198 vector<Edge>edge;
199 vector<int>G[MAXN];
200 vector<Point>polygon;
201 vector<Point>face[MAXN];
202 int vis[2*MAXN],pre[2*MAXN];   //left表示这条边的左侧属于哪个面
203 inline void Init()
204     for(int i=0;i<(int)edge.size();i++)  vis[i]=0;
205     edge.clear();
206     for(int i=0;i<n;i++)    G[i].clear();
207     for(int i=0;i<face_cnt;i++) face[i].clear();
208     n=m=face_cnt=0;
209 
210 inline void AddEdge(int from, int to)             //需要建立反向边帮助寻找下一条边
211     edge.pb(Edge(from,to,(point[to]-point[from]).polar()));
212     edge.pb(Edge(to,from,(point[from]-point[to]).polar()));
213     m=edge.size();
214     G[from].pb(m-2);
215     G[to].pb(m-1);
216 
217 inline void Build()
218     for(int u=0;u<n;u++)
219         int d=G[u].size();
220         for(int i=0;i<d;i++)
221             for(int j=i+1;j<d;j++)
222                 if(edge[G[u][i]].ang>edge[G[u][j]].ang)
223                     swap(G[u][i],G[u][j]);
224         for(int i=0;i<d;i++)    pre[G[u][(i+1)%d]]=G[u][i]; //从u出发的i条边顺时针旋转的第一条边是pre[i]
225     
226     for(int u=0;u<n;u++)
227         for(int i=0;i<(int)G[u].size();i++)
228             int e=G[u][i];
229             if(!vis[e])
230                 while(1)
231                     vis[e]=1;
232                     int from=edge[e].from;
233                     polygon.pb(point[from]);
234                     e=pre[e^1];         //逆时针旋转最多的一条边即为顺时针转动的第一条边
235                     if(e==G[u][i])  break;
236                 
237                 face[face_cnt++]=polygon;
238                 polygon.clear();
239            
240         
241     
242     for(int i=0;i<face_cnt;i++)  area[i]=polygon_area(face[i]);
243 
244 
245 typedef pair<Point,int> pdd;
246 
247 pdd st[MAXN];
248 vector<pair<db,int> >tmp[MAXN];
249 
250 inline bool cmp(pdd x,pdd y)
251     return x.fi.polar()<y.fi.polar();
252 
253 
254 inline void Insert(Line *line,int m)
255     for(int i=0;i<m;i++)
256         for(int j=i+1;j<m;j++)
257             if(!is_parallel(line[i],line[j]))
258                 Point inter=line[i]&line[j];
259                 if(dcmp(inter.len()-10)>0)  continue;
260                 point[n++]=inter;
261             
262     sort(point,point+n);
263     n=unique(point,point+n)-point;
264     for(int i=0;i<n;i++)    point[i].id=i;
265     int cnt=0;
266     for(int i=0;i<n;i++)
267         if(dcmp(point[i].len()-10)==0)
268             st[cnt++]=pdd(point[i],i);
269     sort(st,st+cnt,cmp);
270     st[cnt]=st[0];
271     for(int i=0;i<cnt;i++)   st[i].fi.nx=st[i+1].fi.id;
272     for(int i=0;i<cnt;i++)   point[st[i].se]=st[i].fi;
273     for(int i=0;i<m;i++)
274         for(int j=0;j<n;j++)
275             if(relation(point[j],line[i])==3)
276                 tmp[i].pb(MP(dot(point[j]-line[i].s,line[i].e-line[i].s),j));
277         sort(tmp[i].begin(),tmp[i].end());
278         for(int j=1;j<(int)tmp[i].size();j++)  AddEdge(tmp[i][j-1].se,tmp[i][j].se);
279     
280     for(int i=0;i<m;i++)    tmp[i].clear();
281     Build();
282 
283 
284 typedef pair<db,Point> pd;
285 
286 pd a[MAXN];
287 Line line[MAXN];
288 
289 int main(void)
290     int T;  scanf("%d",&T);
291     while(T--)
292         Init();
293         int n,m=0,k=0;  scanf("%d",&n);
294         for(int i=0;i<n;i++)
295             double x,y; scanf("%lf%lf",&x,&y);
296             db s=x,t=y;
297             Point p1=Point(10*cos(s),10*sin(s));
298             Point p2=Point(10*cos(t),10*sin(t));
299             a[k++]=pd(s,p1);
300             a[k++]=pd(t,p2);
301             line[m++]=Line(p1,p2);
302         
303         sort(a,a+k);
304         k=unique(a,a+k)-a;
305         a[k]=a[0];  a[k].fi+=2*pi;
306         for(int i=0;i<k;i++)
307             Point tmp;
308             if(dcmp(a[i+1].fi-a[i].fi-pi)==0)   tmp=a[i].se.rotate_left();
309             else if(dcmp(a[i+1].fi-a[i].fi-pi)>0)
310                 tmp=a[i].se+a[i+1].se;
311                 tmp=tmp/tmp.len()*-10;
312             
313             else
314                 tmp=a[i].se+a[i+1].se;
315                 tmp=tmp/tmp.len()*10;
316             
317             line[m++]=Line(a[i].se,tmp);
318             line[m++]=Line(tmp,a[i+1].se);
319         
320         Insert(line,m);
321         sort(area,area+face_cnt);
322         printf("%.2f\\n",(double)area[face_cnt-2]);
323     
324     return 0;
325 

以上是关于POJ 3743 LL’s cake(圆+PSLG)的主要内容,如果未能解决你的问题,请参考以下文章

POJ2226(最小顶点覆盖)

POJ 3549 GSM phone(圆+扫描线+最短路)

POJ - 3207 Ikki‘s Story IV - Panda‘s Trick

二维平面深度优先-POJ 1020 Anniversary Cake

POJ 1905 Expanding Rods#二分

Frosh Week HDU3743(逆序数)