1. 程式人生 > >The Doors(幾何+最短路,好題)

The Doors(幾何+最短路,好題)

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. 


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

The output should contain one line of output for each chamber. The line should contain the minimal path length rounded to two decimal places past the decimal point, and always showing the two decimal places past the decimal point. The line should contain no blanks.

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