POJ 3304 Segments(枚举+判断直线与线段相交,问题转化)

题目链接
题目大意:给定n条线段,问是否存在一条直线使得n条线段投影到直线上之后至少有一个交点。
分析:假设存在这么一条直线,那么上面必定存在一个点使得这个点在n条线段上都有投影,那么连接这n个点能够组成一条直线,然后问题就转化成了问:是否存在一条直线使得它与所有线段都有交点。
先考虑若有这么一条直线过所有线段,则我们可以通过不断旋转这条直线,使得这条直线最终被某两个端点束缚住,两点确定一条直线,则我们可以枚举两个端点,然后用这两个端点组成的直线去与n条线段相交,若都相交则yes,否则no。
注意点:精度问题,数据中存在相同点,相同点要特判。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#define lk (k<<1)
#define rk (k<<1|1)
using namespace std;
typedef long long ll;
const double eps=1e-8;
const double pi=acos(-1.0);
const int inf=0x3f3f3f3f;
const int N=1e5+10,M=2e5+10;
int sgn(double x)
{
    
    
    if(fabs(x)<eps) return 0;
    return x>0?1:-1;
}
struct Point
{
    
    
    double x,y;
    Point(double x=0,double y=0):x(x),y(y){
    
    }
    Point operator - (Point a){
    
    return Point(x-a.x,y-a.y);}
};
double cross(Point a,Point b)
{
    
    
    return a.x*b.y-a.y*b.x;
}
struct Line
{
    
    
    Point a;
    Point v;
    Line(){
    
    }
    Line(Point a,Point v):a(a),v(v){
    
    }
};
bool cross_Line(Point a,Point b,Line c)
{
    
    
    double c1=cross(a-c.a,c.v);
    double c2=cross(b-c.a,c.v);
    return sgn(c1)*sgn(c2)<=0;
}
Point p[1001];
int main()
{
    
    
    int t;
    scanf("%d",&t);
    while(t--)
    {
    
    
        int n;
        scanf("%d",&n);
        int cnt=0;
        for(int i=1;i<=n;i++){
    
    
            cnt++;
            scanf("%lf%lf",&p[cnt].x,&p[cnt].y);
            cnt++;
            scanf("%lf%lf",&p[cnt].x,&p[cnt].y);
        }
        int flag=0,ans=0;
        Line tmp;
        for(int i=1;i<=cnt;i++){
    
    
            for(int j=i+1;j<=cnt;j++){
    
    
                if(!sgn(p[i].x-p[j].x)&&!sgn(p[i].y-p[j].y)) continue;
                flag=0;
                tmp=Line(p[i],p[j]-p[i]);
                for(int k=1;k<=cnt;k+=2){
    
    
                    if(!cross_Line(p[k],p[k+1],tmp)){
    
    
                        flag=1;
                        break;
                    }
                }
                if(!flag) {
    
    
                    ans=1;
                    break;
                }
            }
            if(ans) break;
        }
        if(ans) printf("Yes!\n");
        else printf("No!\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/amazingee/article/details/113274959