poj 3304 Segments(判断直线与线段相交)

版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/83536487

题目链接:poj 3304

题目大意:给出n条线段两个端点的坐标,问所有线段投影到一条直线上,如果这些所有投影至少相交于一点就输出Yes!,否则输出No!。

解题思路:

如果存在L的话,能说明什么。。说明L的法线L’肯定能经过所有的线段

若存在一条直线L‘能经过所有线段,说明存在L’经过所有线段的两个端点。

直线肯定经过两个端点。

那么我们只要枚举两个端点P1P2,对每个直线P1P2 遍历所有线段i:1~N,用叉积<=0来判断线段的两个端点L1L2是否在P1P2的两侧,如果找到一组P1P2就能输出YES了

向量P和向量Q,假如 P*Q>0 ,P在Q的顺时针,P*Q<0,则P在Q的逆时针,P*Q=0,则P与Q共线。

(L1P1^L1P2 )*(L2P1^L2P2 )<=0        ^代表外积,如下图


注意:要判断重复点,即P1P2有可能重点,那么只要加判一下就好了。



#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>

using namespace std;

struct point
{
    double x,y;
    point(){}
    point(double _x,double _y){
        x=_x;y=_y;
    }
};

point operator + (point a,point b) {return point(a.x+b.x,a.y+b.y);}
point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}
point operator * (point a,double p) { return point(a.x*p,a.y*p);}
point operator / (point a,double p){ return point(a.x/p,a.y/p);}

struct line{
    point S,E;
    line(){}
    line(point _a,point _b){
        S=_a;E=_b;
    }
}segment[110];


bool operator < (const point &a,const point &b){
    return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
const double esp=1e-8;
int dcmp(double x){
    if(fabs(x)<esp) return 0;
    else return x<0?-1:1;
}
bool operator ==(const point &a,const point &b){
    return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}

double Cross(point a,point b) { return a.x*b.y-a.y*b.x;}
double area2(point a,point b, point c) {return Cross(b-a,c-a);}
double Dot(point A,point B) { return A.x*B.x+A.y*B.y;}///2,点积,即是|a||b|*cos<a,b>,可用来判断角度的范围
double Length(point A) {return sqrt(Dot(A,A));} ///两点之间的距离

int n;
bool check(line A)
{
    if(dcmp(Length(A.E-A.S))==0) return 0;

    for(int i=0;i<n;i++) ///判断该直线A是否相交所有线段
    {
        if(dcmp(area2(segment[i].S,A.S,A.E))*dcmp(area2(segment[i].E,A.S,A.E))>0)
            return false;
    }
    return true;
}

int main()
{
    int ncase;
    scanf("%d",&ncase);

    double x1,y1,x2,y2;

    while(ncase--)
    {
        scanf("%d",&n);

        for(int i=0;i<n;i++){
        scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
        segment[i]=line(point(x1,y1),point(x2,y2));
        }

        bool flag=false;

        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                ///枚举两条线段i,j的某两个端点作为直线
                if(check(line(segment[i].S,segment[j].S))||check(line(segment[i].S,segment[j].E))
                   ||check(line(segment[i].E,segment[j].S))||check(line(segment[i].E,segment[j].E))){
                    flag=true;
                    break;
                    }
            }
        }

        if(flag) puts("Yes!");
        else puts("No!");


    }
    return 0;
}



猜你喜欢

转载自blog.csdn.net/LJD201724114126/article/details/83536487