Poj 3304 Segments 【线段于直线相交】



点击打开链接



题意:


        给你n条线段,问你有没有可能存在一条直线可以让所有线段在这条直线上的投影交于一点。



题解:


        题意可以转化成所有是否存在一直线与所有线段有交点,而要求的直线就是该直线的一条垂线。垂足即是所有线段投影的焦点,

        那么枚举所有线段的端点,来枚举这条直线,因为如果一条直线能能和所有n条线段相交,那么他一定能过两条线段的端点,

        其实可以这样枚举,枚举一个线段的端点,另外一点在另外一条线段从一端点到另外一端点枚举,这样枚举两个线段就行了,但是这样复杂度更高,,


       接下来就是判断线段与直线能否相交,注意还要去重,两个点如果重复会错。


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<cmath>
#define x first
#define y second

const double eps=1e-8;
const double PI=acos(-1.0);
const int maxn=105;
int sgn(double x){
    if(fabs(x)<eps) return 0;
    if(x<0) return -1;
    return 1;
}
struct Point{
    double x,y;
    Point(){}
    Point(double _x,double _y){
        x=_x;y=_y;
    }
    Point operator -(const Point &b)const{
        return Point(x-b.x,y-b.y);
    }
    double operator ^ (const Point &b)const{
        return x*b.y - y*b.x;
    }
};
struct Line{
    Point s,e;
    Line(){}
    Line(Point _s,Point _e){
        s=_s;e=_e;
    }
};
bool Seg_inter_line(Line l1,Line l2){
    return sgn((l2.s-l1.e)^(l1.s-l1.e))*sgn((l2.e-l1.e)^(l1.s-l1.e))<=0;
}
Point p[maxn*2];
Line l[maxn],tl;
int main(){
    int t,n,cnt;
    double x1,x2,y1,y2;
    scanf("%d",&t);
    while(t--){
        cnt=0;
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
            p[++cnt]={x1,y1};
            p[++cnt]={x2,y2};
            l[i]={p[cnt-1],p[cnt]};
        }
        int f=1;
        for(int i=1;i<cnt;++i){
            for(int j=i+1;j<=cnt;++j){
                tl={p[i],p[j]};
                f=1;
                for(int k=1;k<=n;++k){
                    if (fabs(p[i].x-p[j].x) < eps && fabs(p[i].y-p[j].y) < eps) {
                        f=0; break;
                    }
                    if(Seg_inter_line(tl,l[k])==0) {
                        f=0;break;
                    }
                }
                if(f) {break;}
            }if(f) {break;}
        }
        if(f||n<3) puts("Yes!");
        else puts("No!");
    }
	return 0;
}


        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值