POj 1039 直线与线段相交 直线与直线的交点

比较容易理解,如果光线最优的话是可以认为至少与某两个点相切的,因为如果不和某两个点相切,我们可以将光线进行平移和旋转使其至少和某两个点相切,而且结果不会变差。
于是我们可以枚举任意两个顶点确定一条直线作为光线的路径,之后只要看这条光线最多能够射多远即可。一个可行的思路就是首先判定这两个顶点及以前的光线是否在管子内,如果在管子内,再依次去判定光线最远能射到哪里。判定光线是否在管子内可以判定光线与每对顶点的纵截面的交点是否在管子内。

const double eps = 1e-8 ;

double  sig(double x){
        if(fabs(x) < eps) return 0 ;
        return x > 0 ? 1 : -1 ;
}

double  add(double x , double y){
        if(fabs(x+y) < eps*(fabs(x) + fabs(y))) return 0 ;
        return x + y ;
}

struct  Point{
        double x , y ;
        Point(){}
        Point(double _x , double _y):x(_x),y(_y){}
        Point operator + (Point o){
              return Point(add(x , o.x) , add(y , o.y)) ;
        }
        Point operator - (Point o){
              return Point(add(x , -o.x) , add(y , -o.y)) ;
        }
        Point operator * (double o){
              return Point(x*o , y*o) ;
        }
        double operator ^(Point o){
               return add(x*o.y , -y*o.x) ;
        }
        double dist(Point o){
               return sqrt((x-o.x)*(x-o.x) + (y-o.y)*(y-o.y)) ;
        }
        void  read(){
              scanf("%lf%lf" ,&x , &y) ;
        }
};

// 直线p1p2与线段q1q2是否相交
int  intersection(Point p1 , Point p2 , Point q1 , Point q2){
     double d1 = (p2 - p1) ^ (q1 - p1) ;
     double d2 = (p2 - p1) ^ (q2 - p1) ;
     return  sig(d1 * d2) <= 0 ;
}

//直线p1p2 与直线q1q2 的交点 
Point  getintersect(Point p1 , Point p2 , Point q1 , Point q2){
       double d1 = (p2 - p1) ^ (q1 - p1) ;
       double d2 = (p2 - p1) ^ (q2 - q1) ;
       double d3 = (q2 - q1) ^ (q1 - p1) ;
       double d4 = (q2 - q1) ^ (p2 - p1) ;
       if(fabs(d1) < eps) return q1 ;
       if(fabs(d2) < eps) return q2 ;
       double t = d3 / d4 ;
       return  p1 + (p2 - p1) * t ;
}

struct Line{
       Point s , t ;
       Line(){}
       Line(Point _s , Point _t):s(_s),t(_t){}
       int intersect(Line o){ // 直线与线段O是否相交
             return intersection(s , t , o.s , o.t) ;
       }
       Point getinterpoint(Line o){
             return getintersect(s , t , o.s , o.t) ;
       }
       void read(){
            s.read() , t.read() ;
       }
       friend bool operator < (const Line A ,const Line B){
            return A.s.x < B.s.x ;
       }
} ;

const  double  inf = 100000000.0 ;
Point  up[28] , down[28] ;
int    n  ;

double  answer(){
        int i , j , k  ;
        double ans = - inf ;
        for(i = 1 ; i <= n ; i++){
            for(j = 1 ; j <= n ; j++){
                if(i == j) continue  ;
                Line now = Line(up[i] , down[j]) ;
                for(k = 1 ; k <= n ; k++){
                    if(! now.intersect(Line(up[k] , down[k])))
                        break ;
                }
                if(k > n) return inf ;
                if(k > max(i , j)){
                     Line li = Line(up[k-1] , up[k]) ;
                     if(now.intersect(li))
                         ans = max(ans , now.getinterpoint(li).x) ;
                     li = Line(down[k-1] , down[k]) ;
                     if(now.intersect(li))
                         ans = max(ans , now.getinterpoint(li).x) ;
                }
            }
        }
        return ans ;
}

int  main(){
     int i , j , k ;
     while(cin>>n && n){
          for(i = 1 ; i <= n ; i++){
               up[i].read() ;
               down[i] = Point(up[i].x , up[i].y - 1.0) ;
          }
          double s = answer() ;
          if(s == inf) puts("Through all the pipe.") ;
          else  printf("%.2lf\n" , s) ;
     }
     return 0 ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值