POJ 3304 Segments(判断直线与线段是否相交)

http://poj.org/problem?id=3304

等价于是否存在一条直线穿过所有线段

判断直线与线段是否相交:

首先用两点p1,p2确定了一条直线 在用p1,p2分别与计算线段两个端点计算叉乘即可 ,叉乘之积>0就说明线段两端点在直线的同侧,也就是直线不经过此线段

注意顺序不要搞反了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps=1e-8;
const int maxn=100004;
int dcmp(double x) {
    if(fabs(x) < eps) return 0;
    return x < 0 ? -1 : 1;
}
#define Point Vector
struct Vector{
    double x,y;
    Vector(double x=0,double y=0):x(x),y(y){};
    Vector operator + (const Vector &A) const{
        return Vector(x+A.x,y+A.y);
    }
    Vector operator - (const Vector &A) const{
        return Vector(x-A.x,y-A.y);
    }
    Vector operator * (const double &A) const{
        return Vector(x*A,y*A);
    }
    Vector operator / (const double &A) const{
        return Vector(x/A,y/A);
    }
    bool operator == (const Vector &A) const{
        return dcmp(x-A.x)==0&&dcmp(y-A.y)==0;
    }
};
struct Line{
    Point p1,p2;
    Line(){};
    Line(Point p1,Point p2):p1(p1),p2(p2){}
}li[maxn];
bool operator < (Line l1,Line l2){
    if(l1.p1.x==l2.p1.x) return l1.p1.y<l2.p1.y;
    else return l1.p1.x<l2.p1.x;
}
int ans[maxn],num[maxn],n,m;
double U,L,R,D;
double PolarAngle(Vector A){
    return atan2(A.y,A.x);
}
Vector rotate(Vector &A,double a){
    return A=Vector(A.x*cos(a)-A.y*sin(a),A.x*sin(a)+A.y*cos(a));
}
double Dot(Vector A,Vector B){
    return A.x*B.x+A.y*B.y;
}
double Cross(Vector A,Vector B){
    return A.x*B.y-A.y*B.x;
}
double dis(Point p1,Point p2){
    return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
bool solve(Point p1,Point p2){
    if(dcmp(dis(p1,p2))==0) return false;
    for(int i=1;i<=n;i++){
        if(dcmp(Cross(li[i].p1-p1,li[i].p1-p2)*Cross(li[i].p2-p1,li[i].p2-p2))>0) return false;
    }
    return true;
}
int main(){
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            Point p1,p2;
            scanf("%lf%lf%lf%lf",&p1.x,&p1.y,&p2.x,&p2.y);
            li[i]=Line(p1,p2);
        }
        if(n==1) {printf("Yes!\n");continue;}
        int flag=0;
        for(int i=1;i<=n;i++){
            if(solve(li[i].p1,li[i].p2)) {
                //cout<<i<<endl;
                printf("Yes!\n");flag=1;
                break;
            }
            for(int j=i+1;j<=n;j++){
                if(solve(li[i].p1,li[j].p1)) {
                    printf("Yes!\n");flag=1;
                    break;
                }
                if(solve(li[i].p1,li[j].p2)) {
                    printf("Yes!\n");flag=1;
                    break;
                }
                if(solve(li[i].p2,li[j].p1)) {
                    printf("Yes!\n");flag=1;
                    break;
                }
                if(solve(li[i].p2,li[j].p2)) {
                    printf("Yes!\n");flag=1;
                    break;
                }
            }
            if(flag) break;
        }
        if(!flag) printf("No!\n");
    }
}

原文地址:https://www.cnblogs.com/wifimonster/p/10323946.html

时间: 2024-10-07 23:25:35

POJ 3304 Segments(判断直线与线段是否相交)的相关文章

POJ 3304 Segments 判断直线和线段相交

POJ 3304  Segments 题意:给定n(n<=100)条线段,问你是否存在这样的一条直线,使得所有线段投影下去后,至少都有一个交点. 思路:对于投影在所求直线上面的相交阴影,我们可以在那里作一条线,那么这条线就和所有线段都至少有一个交点,所以如果有一条直线和所有线段都有交点的话,那么就一定有解. 怎么确定有没直线和所有线段都相交?怎么枚举这样的直线?思路就是固定两个点,这两个点在所有线段上任意取就可以,然后以这两个点作为直线,去判断其他线段即可.为什么呢?因为如果有直线和所有线段都相

POJ 3304 Segments (直线与线段是否相交)

题目链接 题意 : 能否找出一条直线使得所有给定的线段在该直线上的投影有一个公共点. 思路 : 假设存在一条直线a使得所有线段在该直线上的投影有公共点,则必存在一条垂直于直线a的直线b,直线b与所有线段相交,所以问题又转变为是否存在一条直线与所在所有线段相交. 假设这样的直线存在,则这一条直线可能与某一条或者某些线段的端点重合,也可能不重合.对于那些没有在端点相交的线段,我们可以把这一条直线通过旋转或平移,让其先与一条线段在线段的端点相交(那此时这一条直线与别的线段就在别的线段的中间相交), 然

[poj] 3304 Segments || 判断线段相交

原题 给出n条线段,判断是否有一条直线与所有线段都有交点 若存在这样一条直线,那么一定存在一条至少过两个线段的端点的直线满足条件. 每次枚举两条线段的两个端点,确定一条直线,判断是否与其他线段都有交点. 判断交点: 判断AB和CD是否相交,即判断AC×BD(叉积)和AD×BC(叉积)是否同号 #include<cstdio> #define eps 1e-13 #define N 110 using namespace std; int t,n; struct point { double x

POJ 3304 Segments(计算几何:直线与线段相交)

POJ 3304 Segments 大意:给你一些线段,找出一条直线能够穿过所有的线段,相交包括端点. 思路:遍历所有的端点,取两个点形成直线,判断直线是否与所有线段相交,如果存在这样的直线,输出Yes,但是注意去重. struct Point { double x, y; } P[210]; struct Line { Point a, b; } L[110]; double xmult(Point p1, Point p2, Point p) { return (p1.x-p.x)*(p2.

[POJ 3304]Segments

Segments Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14918   Accepted: 4728 Description Given n segments in the two dimensional space, write a program, which determines if there exists a line such that after projecting these segments

POJ 3304 Segments【叉积】

题意:有n条线段,问有没有一条直线使得所有线段在这条直线上的投影至少有一个共同点. 思路:逆向思维,很明显这个问题可以转化为是否有一条直线穿过所有线段,若有,问题要求的直线与该直线垂直,并且公共点为垂足. 因此只需要枚举每两个端点形成的直线,判断是否和所有线段相交.证明,若存在一条与所有线段相交的直线L,则可以将L平移直到再移动就不满足"与所有线段相交"这个条件时,此时L经过某个线段的一个端点,再将L旋转直到再旋转就不满足“与所有线段相交"这个条件时,肯定与另一个端点相交.

POJ 3304 Segments 基础线段交判断

LINK 题意:询问是否存在直线,使得所有线段在其上的投影拥有公共点 思路:如果投影拥有公共区域,那么从投影的公共区域作垂线,显然能够与所有线段相交,那么题目转换为询问是否存在直线与所有线段相交.判断相交先求叉积再用跨立定理.枚举每个线段的起始结束点作为直线起点终点遍历即可. /** @Date : 2017-07-12 14:35:44 * @FileName: POJ 3304 基础线段交判断.cpp * @Platform: Windows * @Author : Lweleth ([em

POJ 3304 Segments 线段和直线的交点

C - Segments Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 3304 Appoint description:  System Crawler  (2016-05-07) Description Given n segments in the two dimensional space, write a program, w

POJ 3304 Segments (叉乘判断线段相交)

<题目链接> 题目大意: 给出一些线段,判断是存在直线,使得该直线能够经过所有的线段.. 解题思路: 如果有存在这样的直线,过投影相交区域作直线的垂线,该垂线必定与每条线段相交,问题转化为问是否存在一条线和所有线段相交. 如果存在这么一条直线,那么该直线一定能够移成经过两个端点的形式.枚举所有线段的两个端点,判断该直线和所有线段是否相交即可. #include <iostream> #include <math.h> #include <cstdio> us