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

Posted dd-bond

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 3549 GSM phone(圆+扫描线+最短路)相关的知识,希望对你有一定的参考价值。

题目意思是求起点s到终点s的最短路,但是只能在圆的内部和边上走。一种可以想到的方法就是求出所有的交点,然后两两连边并验证合法性,但是这样的交点数规模有n2

我们可以观察发现,我们在圆求并构成的图形中,在其内部的点是不可能成为最短路上的点,只可能是沿着边上的点擦着经过,所以我们需要把在圆内部的所有点都给扣掉,同样可以证明这样的点的规模只有n个,接下来只需要暴力连边,但是连边的时候需要验证这样的点对是否沿着直线可达。我是直接将这条线段暴力和所有圆求交点,左侧端点计为1,右侧端点计为-1,然后用类似于扫描线的做法sort一遍,最后判断线段的两端是否被这个区间包含即可。

最后跑一边dijk就求出答案。

这个方法感觉不是很好.... 还有比我快20倍的orz... 

如果扣的是灰色点那么规模有n2

技术图片

 

如果是外侧点只有n个,绿色点即为可用点,红色和橙色为两条路,则最短路必然擦过外侧点或者起点终点直接相连

技术图片

 

 

 

  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 #include<cassert>
 28 
 29 #define fi first
 30 #define se second
 31 #define pb push_back
 32 #define MP make_pair
 33 
 34 #pragma GCC optimize(3)
 35 #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
 36 
 37 using namespace std;
 38 
 39 typedef long double db;
 40 typedef long long ll;
 41 typedef pair<db,db> Pd;
 42 typedef pair<int,int> P;
 43 typedef pair<ll,ll> Pll;
 44 
 45 const db eps=1e-8;
 46 const int MAXN=1e5+10;
 47 const db pi=acos(-1.0);
 48 const ll INF=0x3f3f3f3f3f3f3f3f;
 49 
 50 inline int dcmp(db x)
 51     if(fabs(x)<eps) return 0;
 52     return (x>0? 1: -1);
 53 
 54 
 55 inline db Sqrt(db x)
 56     return x>0? sqrt(x): 0;
 57 
 58 
 59 inline db sqr(db x) return x*x; 
 60 
 61 struct Point
 62     db x,y;
 63     Point() x=0,y=0; 
 64     Point(db _x,db _y):x(_x),y(_y)
 65     void input()
 66         double _x,_y;
 67         scanf("%lf%lf",&_x,&_y);
 68         x=_x,y=_y;
 69     
 70     void output() printf("%.2f %.2f\\n",(double)x,(double)y); 
 71     friend istream &operator >>(istream &os,Point &b)
 72         os>>b.x>>b.y;
 73         return os;
 74     
 75     friend ostream &operator <<(ostream &os,Point &b)
 76         os<<b.x<< <<b.y;
 77         return os;
 78     
 79     bool operator ==(const Point &b)const
 80         return (dcmp(x-b.x)==0&&dcmp(y-b.y)==0);
 81     
 82     bool operator !=(const Point &b)const
 83         return !((dcmp(x-b.x)==0&&dcmp(y-b.y)==0));
 84     
 85     bool operator <(const Point &b)const
 86         return (dcmp(x-b.x)==0? dcmp(y-b.y)<0 : x<b.x);
 87     
 88     db operator ^(const Point &b)const     //叉积
 89         return x*b.y-y*b.x;
 90     
 91     db operator *(const Point &b)const     //点积
 92         return x*b.x+y*b.y;
 93     
 94     Point operator +(const Point &b)const
 95         return Point(x+b.x,y+b.y);
 96     
 97     Point operator -(const Point &b)const
 98         return Point(x-b.x,y-b.y);
 99     
100     Point operator *(db a)
101         return Point(x*a,y*a);
102     
103     Point operator /(db a)
104         return Point(x/a,y/a);
105     
106     db len2()  //长度平方
107         return sqr(x)+sqr(y);
108     
109     db len()   //长度
110         return Sqrt(len2());
111     
112     Point change_len(db r) //转化为长度为r的向量
113         db l=len();
114         if(dcmp(l)==0)  return *this;  //零向量
115         return Point(x*r/l,y*r/l);
116     
117     Point rotate_left()    //逆时针旋转90度
118         return Point(-y,x);
119     
120     Point rotate_right()   //顺时针旋转90度
121         return Point(y,-x);
122     
123 ;
124 
125 inline db cross(Point a,Point b)   //叉积
126     return a.x*b.y-a.y*b.x;
127 
128 
129 inline db dot(Point a,Point b) //点积
130     return a.x*b.x+a.y*b.y;
131 
132 
133 inline db dis(Point a,Point b) //两点的距离
134     Point p=b-a;    return p.len();
135 
136 
137 struct Line
138     Point s,e;
139     Line()
140     Line(Point _s,Point _e):s(_s),e(_e) //两点确定直线
141     void input()
142         s.input();
143         e.input();
144     
145     db length()    //线段长度
146         return dis(s,e);
147     
148 ;
149 
150 inline db point_to_line(Point p,Line a)   //点到直线距离
151     return fabs(cross(p-a.s,a.e-a.s)/a.length());
152 
153 
154 inline Point projection(Point p,Line a)       //点在直线上的投影
155     return a.s+(((a.e-a.s)*dot(a.e-a.s,p-a.s))/(a.e-a.s).len2());
156 
157 
158 struct Circle
159     Point p;
160     db r;
161     Circle()
162     void input()
163         p.input();
164         double _r;
165         scanf("%lf",&_r);
166         r=_r;
167     
168 ;
169 
170 inline int relation(Point p,Circle a) //点和圆的位置关系  0:圆外    1:圆上   2:圆内
171     db d=dis(p,a.p);
172     if(dcmp(d-a.r)==0)  return 1;
173     return (dcmp(d-a.r)<0? 2: 0);
174 
175 
176 inline int relation(Line a,Circle b)  //直线和圆的位置关系  0:相离   1:相切   2:相交
177     db p=point_to_line(b.p,a);
178     if(dcmp(p-b.r)==0)  return 1;
179     return (dcmp(p-b.r)<0? 2: 0);
180 
181 
182 inline int relation(Circle a,Circle v)    //圆和圆的位置关系  1:内含  2:内切  3:相交   4:外切   5:相离
183     db d=dis(a.p,v.p);
184     if(dcmp(d-a.r-v.r)>0)   return 5;
185     if(dcmp(d-a.r-v.r)==0)  return 4;
186     db l=fabs(a.r-v.r);
187     if(dcmp(d-l)>0)     return 3;
188     if(dcmp(d-l)==0)    return 2;
189     return 1;
190 
191 
192 inline int circle_intersection(Circle a,Circle v,Point &p1,Point &p2) //两个圆的交点
193     int rel=relation(a,v);                                      //返回交点个数,保存在引用中
194     if(rel==1||rel==5)  return 0;
195     db d=dis(a.p,v.p);
196     db l=(d*d+a.r*a.r-v.r*v.r)/(2*d);
197     db h=Sqrt(a.r*a.r-l*l);
198     Point tmp=a.p+(v.p-a.p).change_len(l);
199     p1=tmp+((v.p-a.p).rotate_left().change_len(h));
200     p2=tmp+((v.p-a.p).rotate_right().change_len(h));
201     if(rel==2||rel==4)  return 1;
202     return 2;
203 
204 
205 inline int line_circle_intersection(Line v,Circle u,Point &p1,Point &p2)  //直线和圆的交点
206     if(!relation(v,u))  return 0;                                   //返回交点个数,保存在引用中
207     Point a=projection(u.p,v);
208     db d=point_to_line(u.p,v);
209     d=Sqrt(u.r*u.r-d*d);
210     if(dcmp(d)==0)
211         p1=a,p2=a;
212         return 1;
213     
214     p1=a+(v.e-v.s).change_len(d);
215     p2=a-(v.e-v.s).change_len(d);
216     return 2;
217 
218 
219 typedef pair<db,int>pdi;
220 typedef pair<Point,int> pd;
221 
222 vector<pdi>edge[MAXN];
223 
224 db d[MAXN];
225 pd st[MAXN];
226 bool mark[MAXN];
227 Circle circle[MAXN];
228 Point s,t,it1,it2,inter[MAXN],point[MAXN];
229 
230 priority_queue<pdi,vector<pdi>,greater<pdi> >q;
231 
232 bool cmp(pd a,pd b)
233     if(a==b)    return a.se>b.se;
234     return a<b;
235 
236 
237 int main(void)
238     s.input();  t.input();
239     int n,m=1,cnt=1;  scanf("%d",&n);
240     for(int i=1;i<=n;i++)   circle[i].input();
241     for(int i=1;i<=n;i++)
242         for(int j=i+1;j<=n;j++)
243             int p=relation(circle[i],circle[j]);
244             if(p==2||p==3||p==4)
245                 circle_intersection(circle[i],circle[j],it1,it2);
246                 point[m++]=it1,point[m++]=it2;
247             
248         
249     sort(point+1,point+m);
250     m=unique(point+1,point+m)-point;
251     for(int i=1;i<m;i++)
252         for(int j=1;j<=n;j++)
253             if(relation(point[i],circle[j])==2)
254                 mark[i]=1;
255                 break;
256             
257     for(int i=1;i<m;i++)
258         if(mark[i]==0)
259             point[cnt++]=point[i];
260     m=cnt;  point[0]=s,point[m]=t;
261     for(int i=0;i<=m;i++)
262         for(int j=i+1;j<=m;j++)
263             int p=0;
264             Line l(point[i],point[j]);
265             Point p1=point[i],p2=point[j];
266             if(p2<p1)   swap(p1,p2);
267             for(int k=1;k<=n;k++)
268                 Circle c=circle[k];
269                 if(relation(l,c))
270                     line_circle_intersection(l,c,it1,it2);
271                     if(it2<it1) swap(it1,it2);
272                     st[p++]=pd(it1,1);
273                     st[p++]=pd(it2,-1);
274                 
275             
276             int found=0;
277             sort(st,st+p,cmp);
278             for(int k=0,sum=0,start=0;k<p;k++)
279                 sum+=st[k].se;
280                 if(sum==0)
281                     if(!(p1<st[start].fi)&&!(st[k].fi<p2)) found=1;
282                     start=k+1;
283                 
284             
285             if(found)
286                 edge[i].pb(pdi(l.length(),j));
287                 edge[j].pb(pdi(l.length(),i));
288             
289         
290     for(int i=1;i<=m;i++)   d[i]=1e20;
291     q.push(pdi(0,0));
292     while(!q.empty())
293         pdi p=q.top();  q.pop();
294         if(dcmp(d[p.se]-p.fi)<0)   continue;
295         for(int i=0;i<edge[p.se].size();i++)
296             int v=edge[p.se][i].se;
297             db val=edge[p.se][i].fi;
298             if(dcmp(d[p.se]+val-d[v])<0)
299                 d[v]=d[p.se]+val;
300                 q.push(pdi(d[v],v));
301             
302         
303     
304     printf("%.5f\\n",(double)d[m]);
305     return 0;
306 

以上是关于POJ 3549 GSM phone(圆+扫描线+最短路)的主要内容,如果未能解决你的问题,请参考以下文章

POJ 2932 Coneology计算最外层圆个数

POJ 2932 Coneology (平面扫描)

HDU 3511 圆扫描线

poj 2932 Coneology (扫描线)

POJ 2932 Coneology (扫描线判断最外面的圆&set维护最近的圆)

POJ - 1981 :Circle and Points (圆的扫描线) hihocoder1508