• 求射线与线段相交的最多交点 poj 4048


    题目来源:http://poj.org/problem?id=4048

    Problem E. Chinese Repeating Crossbow
    Description
    In Chinese history, Zhuge Liang, prime minister of Shu in three kingdoms period,
    is regarded as the embodiment of wisdom. When he was dying he passed a book to
    his apprentice Jiang Wei privately. This book recorded the introduction and
    specification of a most powerful weapon at that time, called Chinese repeating
    crossbow or Zhuge repeating crossbow (Figure 1). This weapon can shoot many
    arrows in a very short time and makes enemies very hard to defense it.

    Figure 1 Chinese Repeating Crossbow
    Later on, Jiang Wei built a repeating crossbow according to the book and he
    wanted to know exactly about its power. He came to the center of a test field. The test
    field was ragged with several extreme high straw walls. Jiang Wei wanted to choose a
    direction, shot through as many straw walls as he can by his new weapon.
    The problem given to you is quite simple: assuming that the repeating crossbow
    can shot through any numbers of straw walls, please help Jiang Wei to choose a
    certain direction that he can shot through maximum number of walls in one shot. The
    walls can be considered as line segments, and if an arrow touches the end points of a
    wall, it's also called "shoot through". The straw walls can intersect or overlap with
    each other, and Jiang Wei may possibly stand extremely close to one of the straw wall.
    Input
    The first line of the input contains an integer T (T<=10) representing the number
    of test cases.
    In each test case, the first line contains an integer N (0<N<=1500) representing
    the number of straw walls on the field. Each of the following N lines contains four
    integer numbers x1, y1, x2, y2,which describes the end point (x1, y1) and (x2, y2) of a
    straw wall. The last line of the test case contains two integer (x, y) representing the
    position of Jiang Wei. All the coordinates are integer numbers and in the range of
    [-10000, 10000].
    Output
    For each test case, output a single integer representing the maximum number of straw walls can be shot through in one shot.
    Sample Input
    2
    3
    -1 -1 1 -1
    -1 1 1 1
    -1 2 1 2
    0 0
    3
    -1 -1 1 -1
    -1 0 0 1
    1 0 0 1
    0 0
    Sample Output
    2
    2

    分析: 求与线段相交最多交点的射线一定 经过线段的某端点。 求该射线与线段的交点 转换为 求 线段与线段的交点, 即 将射线 转换成 线段。通过斜率,

    确定射线另一端端点C 的坐标。

    设固定点为 A, 射线的经过的一个线段端点为 B ,  分两种情况:

    1: AB 斜率不存在 ,即 若A.x == B.x  。

        若B.x> A.x  则设 另一端点C 的坐标为(A.x, 10008), 

        若B.x<A.x  则设 另一端点C 的坐标为(A.x, -10008), 

    2:AB 斜率存在,  k= (B.y-A.y) / (B.x-A.x)

        若B.x> A.x 则设 另一端点C的坐标为 (10008, A.y+ k ( 10008 - A.x))

        若B.x<A.x ,则另一端点C的坐标为 (-10008, A.y+k(-10008 - A.x))

    由于斜率是  double ,故需要考虑精度问题,虽然输入输出为 int,我们用 double 处理数据。

    代码如下:

    #include <iostream>
    #include <algorithm>
    #include <stdlib.h>
    #include <stack>
    #include <iostream>
    #include <stdio.h>
    #include <string>
    #include <string.h>
    #include <algorithm>
    #include <stdlib.h>
    #include <vector>
    #include <set>
    #include <math.h>
    #include <cmath>
    #include <map>
    #include <stack>
    #include <queue>
    
    using namespace std ;
    
    double EPS=1e-10;
    // 考虑误差的加法运算
    double add(double a,double b)
    {
        if(fabs(a+b)<EPS*(fabs(a)+fabs(b))) return 0;
        return a+b;
    }
    struct Point{
        double x,y;
        Point(){}
        Point(double x,double y):x(x),y(y){} // 构造函数,方便代码编写
        Point operator +(Point p){
            return Point(add(x,p.x), add(y,p.y));
        }
        Point operator-(Point p){
            return Point(add(x,-p.x),add(y,-p.y));
        }
        Point operator*(double d){
            return Point(x*d,y*d);
        }
        double operator*(Point p){  // 内积 点乘
            return add(x*p.x, y*p.y);
        }
        double operator^(Point p){//  外积 叉乘
            return add(x*p.y,-y*p.x);
        }
    };
    //判断点p0是否在线段p1p2内
    int on_segment(Point p1, Point p2, Point p0)
    {
        if (((p1-p0).x * (p2-p0).x <=0 )&& ((p1-p0).y * (p2-p0).y <=0))   // 中间是 &&
            return 1;
        return 0;
    }
    // 判断线段p1p2与q1是否相交
    int intersection(Point p1,Point p2, Point q1,Point q2)
    {
        double d1=(p2-p1)^(q1-p1);           // 计算p1p2 到q 点的转向 d1>0 左转,  d1 <0 右转
        double d2=(p2-p1)^(q2-p1);
        double d3=(q2-q1)^(p1-q1);
        double d4=(q2-q1)^(p2-q1);
        if((d1==0 && on_segment(p1,p2,q1) )|| (d2==0 && on_segment(p1,p2,q2) )||
           (d3==0&& on_segment(q1,q2,p1)) || (d4==0 && on_segment(q1,q2,p2)))
           return 1;
        else if(d1*d2<0 && d3*d4 <0)    // 中间是 &&
            return 1;
        return 0;
    }
    
    struct Line{
           Point st ;
           Point ed ;
           Line(){}
           Line(Point a , Point b){
               st = a ;
               ed = b ;
           }
           void read(){
                scanf("%lf%lf%lf%lf" , &st.x , &st.y , &ed.x , &ed.y) ;
           }
    };
    
    const double Max_p  = 10008 ;
    Line Getshexian(Point A , Point B){
         if(A.x == B.x){
              if(B.y >= A.y)
                  return Line(A , Point(A.x , Max_p)) ;
              else
                  return Line(A , Point(A.x ,-Max_p)) ;
         }
         if(B.x > A.x){
               double k = (B.y - A.y) / (B.x - A.x)  ;
               double y = (Max_p -A.x)* k + A.y ;
               return Line(A , Point(Max_p , y)) ;
         }
         else{
               double k = (B.y - A.y) / (B.x - A.x)  ;
               double y = (-Max_p -A.x)* k + A.y ;
               return Line(A , Point(-Max_p , y)) ;
         }
    }
    
    Line line[1508] ;
    
    int n ;
    
    int Ans(Line she){
        int i , ans = 0 ;
        for(i = 1 ; i <= n ; i++){
             if(intersection(she.st , she.ed , line[i].st  , line[i].ed))
                  ans++ ;
        }
        return ans ;
    }
    
    int main() {
        int i , ans , t,sum ;
        Point A ;
        cin>>t ;
        while(t--){
             scanf("%d" ,&n) ;
             for(i = 1 ; i <= n ; i++)
                 line[i].read() ;
             scanf("%lf%lf" ,&A.x ,&A.y) ;
             ans = 0 ;
             for(i = 1 ; i <= n ; i++){
                 Line now = Getshexian(A , line[i].st) ;
                 ans = max(ans , Ans(now)) ;
                 now = Getshexian(A , line[i].ed) ;
                 ans = max(ans , Ans(now)) ;
             }
             cout<<ans<<endl ;
        }
        return 0;
    }
  • 相关阅读:
    ESP8266-12F引脚接法
    esp8266物联网开发六:让ESP32-CAM五彩斑斓
    esp8266物联网开发五:SSL保驾护航
    esp8266物联网开发四:MQTT再论部控
    esp8266物联网开发三:MQTT初窥貌容
    esp8266物联网开发二:Arduino名门正派
    esp8266物联网开发一:MicroPython初战江湖
    一些错误记录
    jimdb压测踩坑记
    Caffeine批量加载浅析
  • 原文地址:https://www.cnblogs.com/zn505119020/p/3625546.html
Copyright © 2020-2023  润新知