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 }