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 ;
}


你可能感兴趣的:(POj 1039 直线与线段相交 直线与直线的交点)