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

有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

猜你喜欢

转载自www.cnblogs.com/Fighting-sh/p/9927622.html