poj 1556 线段相交加最短路

题意:在平面直角坐标系上有一个10*10的正方形房间,房间中有n堵平行y方向的墙,每堵墙上有两扇门,

问从房间最左边的(0,5)处,通过门,到达房间最右边的(10,5)处的最短距离

题解:考虑从起始点,若沿x轴走则可以一直走到被墙堵住为止,此时其需要走到堵住它的墙的门的端点,一定可以转化成更早就从某一个门的端点开始走距离更短,可以考虑成两点AB之间,不能直接用线段相连,那么是一直走平行于X轴的直线然后转折到另一个点,还是直接走更趋近于AB的斜线然后转折,明显后一种距离更短。

把起点和终点和门上所有端点设想为图上的点,每两个点之间建边,如果两点之间会被墙阻隔则设为无穷大,因为数据很小,可以随便遍历,不用太考虑时间复杂度

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <vector>
  4 #include <algorithm>
  5 #include <iostream>
  6 #include <map>
  7 #include <queue>
  8 #include <stack>
  9 #include <cmath>
 10 //#pragma comment(linker, "/STACK:102400000,102400000")
 11 using namespace std;
 12 #define PF(x) cout << "debug: " << x << " ";
 13 #define EL cout << endl;
 14 #define PC(x) puts(x);
 15 typedef long long ll;
 16 #define CLR(x, v) sizeof (x, v, sizeof(x))
 17 using namespace std;
 18 const int INF = 0x5f5f5f5f;
 19 const int  N= 2e5 + 10;
 20 const int mod=1e9 + 7;
 21 const int maxn = 100;
 22 const double eps = 1e-8;
 23 const double PI = acos(-1.0);
 24 int t;
 25 int sgn(double x){
 26     if(fabs(x) < eps) return 0;
 27     if(x < 0) return -1;
 28     else return 1;
 29 
 30 }
 31 struct Point{
 32     double x,y;
 33     Point() { }
 34     Point(double _x,double _y){
 35         x = _x,y = _y;
 36     }
 37     Point operator - (const Point &b) const{ //相对坐标
 38         return Point(x - b.x,y - b.y);
 39     }
 40     double operator ^(const Point &b)const{//叉积
 41         return x*b.y - y*b.x;
 42     }
 43     double operator *(const Point &b)const{//点积
 44         return x*b.x + y*b.y;
 45     }
 46     void transXY(double B){
 47         double tx = x,ty = y;
 48         x = tx*cos(B) - ty*sin(B);
 49         y = tx*sin(B) + ty*cos(B);
 50     }
 51 };
 52 struct Line{
 53     Point s,e;
 54     Line() { }
 55     Line (Point _s,Point _e){
 56         s = _s,e = _e;
 57     }
 58     //两直线相交求交点
 59     //第一个值为0表示直线重合,为1表示平行,为2是相交
 60     //只有第一个值为2时交点才有意义
 61     pair<int,Point> operator &(const Line &b) const{
 62         Point res = s;
 63         if(sgn((s-e)^(b.s-b.e)) == 0){
 64             if(sgn((s-b.e)^(b.s-b.e)) == 0)
 65                 return make_pair(0,res);//重合
 66             else
 67                 return make_pair(1,res);
 68         }
 69         double t = ((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));
 70         res.x += (e.x-s.x)*t;
 71         res.y += (e.y-s.y)*t;
 72         return make_pair(2,res);
 73     }
 74 };
 75 double dist(Point a,Point b){
 76     return sqrt((b-a)*(b-a));
 77 }
 78 bool Seg_inter_line(Line l1,Line l2){//判断直线l1与线段l2是否相交
 79     return sgn((l2.s - l1.e) ^ (l1.s-l1.e)) * sgn((l2.e-l1.e)^(l1.s-l1.e)) <= 0;
 80 }
 81 bool inter(Line l1,Line l2){
 82     return max(l1.s.x,l1.e.x) >= min(l2.s.x,l2.e.x) &&
 83     max(l2.s.x,l2.e.x) >= min(l1.s.x,l1.e.x) &&
 84     max(l1.s.y,l1.e.y) >= min(l2.s.y,l2.e.y) &&
 85     max(l2.s.y,l2.e.y) >= min(l1.s.y,l1.e.y) &&
 86     sgn((l2.s-l1.e)^(l1.s-l1.e))*sgn((l2.e-l1.e)^(l1.s-l1.e)) <= 0&&
 87     sgn((l1.s-l2.e)^(l2.s-l2.e))*sgn((l1.e-l2.e)^(l2.s-l2.e)) <= 0;
 88 
 89 }
 90 int n,cntl,cntp;
 91 double gra[maxn][maxn];
 92 Line line[maxn];
 93 Point pt[maxn];
 94 void flyod(){
 95     for(int k = 1;k <= cntp;k++)
 96         for(int i = 1;i <= cntp;i++)
 97             for(int j = 1;j <= cntp;j++)
 98                 gra[i][j] = min(gra[i][j],gra[i][k]+gra[k][j]);
 99 
100 }
101 bool cek(Line l){
102     for(int i = 1;i <= cntl;i++){
103         if(dist(line[i].s,l.s) == 0||dist(line[i].s,l.e) == 0||dist(line[i].e,l.s) == 0||dist(line[i].e,l.e) == 0)
104         continue;
105         if(inter(l,line[i]))
106             return false;
107     }
108     return true;
109 }
110 int main()
111 {
112   // freopen("in.txt","r",stdin);
113     while(~scanf("%d",&n)){
114         if(n == -1)
115             break;
116         double x,h1,h2,h3,h4;
117         cntl = 0,cntp = 2;
118         for(int i = 1;i < 100;i++)
119             for(int j = 1;j <100;j++)
120                 gra[i][j] = 10000.0;
121         pt[1] = Point(0,5);
122         pt[2] = Point(10,5);
123         for(int i = 1;i <= n;i++){
124             scanf("%lf%lf%lf%lf%lf",&x,&h1,&h2,&h3,&h4);
125             line[++cntl] = Line(Point(x,0),Point(x,h1));
126             line[++cntl] = Line(Point(x,h2),Point(x,h3));
127             line[++cntl] = Line(Point(x,h4),Point(x,10));
128             pt[++cntp] = Point(x,h1);
129             pt[++cntp] = Point(x,h2);
130             pt[++cntp] = Point(x,h3);
131             pt[++cntp] = Point(x,h4);
132         }
133         for(int i = 1;i <= cntp;i++)
134             for(int j = i;j <= cntp;j++){
135                 if(i == j){
136                     gra[i][i] = 0;
137                     continue;
138                 }
139                 Line l = Line(pt[i],pt[j]);
140                 if(cek(l)){
141                     gra[i][j] = dist(pt[i],pt[j]);
142                     gra[j][i] = gra[i][j];
143                 }
144 
145             }
146         flyod();
147         printf("%.2f\n",gra[1][2]);
148     }
149     return 0;
150 }

 

转载于:https://www.cnblogs.com/shimu/p/5832729.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值