The Doors(幾何+最短路,好題)
阿新 • • 發佈:2018-11-08
The Doors
http://poj.org/problem?id=1556
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 10466 | Accepted: 3891 |
Description
You are to find the length of the shortest path through a chamber containing obstructing walls. The chamber will always have sides at x = 0, x = 10, y = 0, and y = 10. The initial and final points of the path are always (0, 5) and (10, 5). There will also be from 0 to 18 vertical walls inside the chamber, each with two doorways. The figure below illustrates such a chamber and also shows the path of minimal length.Input
The input data for the illustrated chamber would appear as follows.2
4 2 7 8 9
7 3 4.5 6 7
The first line contains the number of interior walls. Then there is a line for each such wall, containing five real numbers. The first number is the x coordinate of the wall (0 < x < 10), and the remaining four are the y coordinates of the ends of the doorways in that wall. The x coordinates of the walls are in increasing order, and within each line the y coordinates are in increasing order. The input file will contain at least one such set of data. The end of the data comes when the number of walls is -1.
Output
Sample Input
1 5 4 6 7 8 2 4 2 7 8 9 7 3 4.5 6 7 -1
Sample Output
10.00 10.06
Source
Mid-Central USA 1996
有18堵牆!!!因為沒看清這個瘋狂爆RE
poj上交C++會CE,要自己寫hypot函式
double hypot(double x,double y){ return sqrt(x*x+y*y); }
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cmath> 5 #include<vector> 6 #include<algorithm> 7 using namespace std; 8 const double eps=1e-8; 9 const double INF=1e20; 10 const double PI=acos(-1.0); 11 const int maxp=1010; 12 int sgn(double x){ 13 if(fabs(x)<eps) return 0; 14 if(x<0) return -1; 15 else return 1; 16 } 17 inline double sqr(double x){return x*x;} 18 struct Point{ 19 double x,y; 20 Point(){} 21 Point(double _x,double _y){ 22 x=_x; 23 y=_y; 24 } 25 void input(){ 26 scanf("%lf %lf",&x,&y); 27 } 28 void output(){ 29 printf("%.2f %.2f\n",x,y); 30 } 31 bool operator == (const Point &b)const{ 32 return sgn(x-b.x) == 0 && sgn(y-b.y)== 0; 33 } 34 bool operator < (const Point &b)const{ 35 return sgn(x-b.x)==0?sgn(y-b.y)<0:x<b.x; 36 } 37 Point operator - (const Point &b)const{ 38 return Point(x-b.x,y-b.y); 39 } 40 //叉積 41 double operator ^ (const Point &b)const{ 42 return x*b.y-y*b.x; 43 } 44 //點積 45 double operator * (const Point &b)const{ 46 return x*b.x+y*b.y; 47 } 48 //返回長度 49 double len(){ 50 return hypot(x,y); 51 } 52 //返回長度的平方 53 double len2(){ 54 return x*x+y*y; 55 } 56 //返回兩點的距離 57 double distance(Point p){ 58 return hypot(x-p.x,y-p.y); 59 } 60 Point operator + (const Point &b)const{ 61 return Point(x+b.x,y+b.y); 62 } 63 Point operator * (const double &k)const{ 64 return Point(x*k,y*k); 65 } 66 Point operator / (const double &k)const{ 67 return Point(x/k,y/k); 68 } 69 70 //計算pa和pb的夾角 71 //就是求這個點看a,b所成的夾角 72 ///LightOJ1202 73 double rad(Point a,Point b){ 74 Point p=*this; 75 return fabs(atan2(fabs((a-p)^(b-p)),(a-p)*(b-p))); 76 } 77 //化為長度為r的向量 78 Point trunc(double r){ 79 double l=len(); 80 if(!sgn(l)) return *this; 81 r/=l; 82 return Point(x*r,y*r); 83 } 84 //逆時針轉90度 85 Point rotleft(){ 86 return Point(-y,x); 87 } 88 //順時針轉90度 89 Point rotright(){ 90 return Point(y,-x); 91 } 92 //繞著p點逆時針旋轉angle 93 Point rotate(Point p,double angle){ 94 Point v=(*this) -p; 95 double c=cos(angle),s=sin(angle); 96 return Point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c); 97 } 98 }; 99 100 struct Line{ 101 Point s,e; 102 Line(){} 103 Line(Point _s,Point _e){ 104 s=_s; 105 e=_e; 106 } 107 bool operator==(Line v){ 108 return (s==v.s)&&(e==v.e); 109 } 110 //根據一個點和傾斜角angle確定直線,0<=angle<pi 111 Line(Point p,double angle){ 112 s=p; 113 if(sgn(angle-PI/2)==0){ 114 e=(s+Point(0,1)); 115 } 116 else{ 117 e=(s+Point(1,tan(angle))); 118 } 119 } 120 //ax+by+c=0; 121 Line(double a,double b,double c){ 122 if(sgn(a)==0){ 123 s=Point(0,-c/b); 124 e=Point(1,-c/b); 125 } 126 else if(sgn(b)==0){ 127 s=Point(-c/a,0); 128 e=Point(-c/a,1); 129 } 130 else{ 131 s=Point(0,-c/b); 132 e=Point(1,(-c-a)/b); 133 } 134 } 135 void input(){ 136 s.input(); 137 e.input(); 138 } 139 void adjust(){ 140 if(e<s) swap(s,e); 141 } 142 //求線段長度 143 double length(){ 144 return s.distance(e); 145 } 146 //返回直線傾斜角 0<=angle<pi 147 double angle(){ 148 double k=atan2(e.y-s.y,e.x-s.x); 149 if(sgn(k)<0) k+=PI; 150 if(sgn(k-PI)==0) k-=PI; 151 return k; 152 } 153 //點和直線的關係 154 //1 在左側 155 //2 在右側 156 //3 在直線上 157 int relation(Point p){ 158 int c=sgn((p-s)^(e-s)); 159 if(c<0) return 1; 160 else if(c>0) return 2; 161 else return 3; 162 } 163 //點線上段上的判斷 164 bool pointonseg(Point p){ 165 return sgn((p-s)^(e-s))==0&&sgn((p-s)*(p-e))<=0; 166 } 167 //兩向量平行(對應直線平行或重合) 168 bool parallel(Line v){ 169 return sgn((e-s)^(v.e-v.s))==0; 170 } 171 //兩線段相交判斷 172 //2 規範相交 173 //1 非規範相交 174 //0 不相交 175 int segcrossseg(Line v){ 176 int d1=sgn((e-s)^(v.s-s)); 177 int d2=sgn((e-s)^(v.e-s)); 178 int d3=sgn((v.e-v.s)^(s-v.s)); 179 int d4=sgn((v.e-v.s)^(e-v.s)); 180 if((d1^d2)==-2&&(d3^d4)==-2) return 2; 181 return (d1==0&&sgn((v.s-s)*(v.s-e))<=0|| 182 d2==0&&sgn((v.e-s)*(v.e-e))<=0|| 183 d3==0&&sgn((s-v.s)*(s-v.e))<=0|| 184 d4==0&&sgn((e-v.s)*(e-v.e))<=0); 185 } 186 //直線和線段相交判斷 187 //-*this line -v seg 188 //2 規範相交 189 //1 非規範相交 190 //0 不相交 191 int linecrossseg(Line v){ 192 int d1=sgn((e-s)^(v.s-s)); 193 int d2=sgn((e-s)^(v.e-s)); 194 if((d1^d2)==-2) return 2; 195 return (d1==0||d2==0); 196 } 197 //兩直線關係 198 //0 平行 199 //1 重合 200 //2 相交 201 int linecrossline(Line v){ 202 if((*this).parallel(v)) 203 return v.relation(s)==3; 204 return 2; 205 } 206 //求兩直線的交點 207 //要保證兩直線不平行或重合 208 Point crosspoint(Line v){ 209 double a1=(v.e-v.s)^(s-v.s); 210 double a2=(v.e-v.s)^(e-v.s); 211 return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1)); 212 } 213 //點到直線的距離 214 double dispointtoline(Point p){ 215 return fabs((p-s)^(e-s))/length(); 216 } 217 //點到線段的距離 218 double dispointtoseg(Point p){ 219 if(sgn((p-s)*(e-s))<0||sgn((p-e)*(s-e))<0) 220 return min(p.distance(s),p.distance(e)); 221 return dispointtoline(p); 222 } 223 //返回線段到線段的距離 224 //前提是兩線段不相交,相交距離就是0了 225 double dissegtoseg(Line v){ 226 return min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v.dispointtoseg(s),v.dispointtoseg(e))); 227 } 228 //返回點P在直線上的投影 229 Point lineprog(Point p){ 230 return s+(((e-s)*((e-s)*(p-s)))/((e-s).len2())); 231 } 232 //返回點P關於直線的對稱點 233 Point symmetrypoint(Point p){ 234 Point q=lineprog(p); 235 return Point(2*q.x-p.x,2*q.y-p.y); 236 } 237 }; 238 239 Line L[1005]; 240 int n; 241 242 bool Check(Line a,Line b){ 243 if(sgn((a.s-a.e)^(b.s-a.e))*sgn((a.s-a.e)^(b.e-a.e))>0) return false; 244 if(sgn((b.s-b.e)^(a.s-b.e))*sgn((b.s-b.e)^(a.e-b.e))>0) return false; 245 if(sgn(max(a.s.x,a.e.x)-min(b.s.x,b.e.x))>=0&&sgn(max(b.s.x,b.e.x)-min(a.s.x,a.e.x))>=0 246 &&sgn(max(a.s.y,a.e.y)-min(b.s.y,b.e.y))>=0&&sgn(max(b.s.y,b.e.y)-min(a.s.y,a.e.y))>=0) 247 return true; 248 else return false; 249 } 250 251 252 double mp[115][115]; 253 254 int co; 255 256 void panduan(Line a,int xx,int yy){ 257 if(a.s.y==0||a.s.y==10||a.e.y==0||a.e.y==10) return; 258 for(int i=1;i<co;i++){ 259 if(i!=(xx+1)/2&&i!=(yy+1)/2){ 260 if(Check(a,L[i])){ 261 return; 262 } 263 } 264 } 265 //cout<<xx<<" "<<yy<<" "<<a.length()<<endl; 266 267 mp[xx][yy]=mp[yy][xx]=a.length(); 268 } 269 270 int main(){ 271 while(~scanf("%d",&n)){ 272 if(n==-1) break; 273 double x,y1,y2,y3,y4; 274 co=1; 275 for(int i=0;i<115;i++){ 276 for(int j=0;j<115;j++){ 277 mp[i][j]=INF; 278 } 279 } 280 Point s,e; 281 s.x=0,s.y=5; 282 e.x=10,e.y=5; 283 //起點為0,終點為co 284 for(int i=1;i<=n;i++){ 285 scanf("%lf %lf %lf %lf %lf",&x,&y1,&y2,&y3,&y4); 286 L[co].s.x=x,L[co].s.y=0,L[co].e.x=x,L[co++].e.y=y1; 287 L[co].s.x=x,L[co].s.y=y2,L[co].e.x=x,L[co++].e.y=y3; 288 L[co].s.x=x,L[co].s.y=y4,L[co].e.x=x,L[co++].e.y=10; 289 } 290 291 Line tmp; 292 int j; 293 //不包括起點和終點的建圖 294 for(int i=1;i<co;i++){ 295 for(int j=i+1;j<co;j++){ 296 tmp.s=L[i].s,tmp.e=L[j].s; 297 panduan(tmp,(i-1)*2+1,(j-1)*2+1); 298 tmp.s=L[i].s,tmp.e=L[j].e; 299 panduan(tmp,(i-1)*2+1,(j-1)*2+2); 300 tmp.s=L[i].e,tmp.e=L[j].s; 301 panduan(tmp,(i-1)*2+2,(j-1)*2+1); 302 tmp.s=L[i].e,tmp.e=L[j].e; 303 panduan(tmp,(i-1)*2+2,(j-1)*2+2); 304 } 305 } 306 //加上起點和終點 307 for(int i=1;i<co;i++){ 308 tmp.s=s,tmp.e=L[i].s; 309 panduan(tmp,0,(i-1)*2+1); 310 tmp.s=s,tmp.e=L[i].e; 311 panduan(tmp,0,(i-1)*2+2); 312 tmp.s=e,tmp.e=L[i].s; 313 panduan(tmp,(i-1)*2+1,114); 314 tmp.s=e,tmp.e=L[i].e; 315 panduan(tmp,(i-1)*2+2,114); 316 } 317 tmp.s=s,tmp.e=e; 318 panduan(tmp,0,114); 319 for(int k=0;k<=114;k++) 320 for(int i=0;i<=114;i++) 321 for(int j=0;j<=114;j++) 322 if(mp[i][j]>mp[i][k]+mp[k][j]+eps) 323 mp[i][j]=mp[i][k]+mp[k][j]; 324 printf("%.2f\n",mp[0][114]); 325 } 326 return 0; 327 }View Code