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

POJ 3304  Segments

题意:给定n(n<=100)条线段,问你是否存在这样的一条直线,使得所有线段投影下去后,至少都有一个交点。

思路:对于投影在所求直线上面的相交阴影,我们可以在那里作一条线,那么这条线就和所有线段都至少有一个交点,所以如果有一条直线和所有线段都有交点的话,那么就一定有解。

怎么确定有没直线和所有线段都相交?怎么枚举这样的直线?思路就是固定两个点,这两个点在所有线段上任意取就可以,然后以这两个点作为直线,去判断其他线段即可。为什么呢?因为如果有直线和所有线段都相交,那么我绝对可以平移到某个极限的端点位置,再旋转到某个极限的端点位置,也不会失去正解。Bug点就是枚举的两个点是重点的话,这个直线的方向向量是0向量,这样会判断到与所有线段都相交。~~

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>

const int maxn = 5000+20;
struct coor
{
    double x,y;
    coor(){}
    coor(double xx,double yy):x(xx),y(yy){}
    double operator ^(coor rhs) const //计算叉积(向量积)
    {
        return x*rhs.y - y*rhs.x;
    }
    coor operator -(coor rhs) const //坐标相减,a-b得到向量ba
    {
        return coor(x-rhs.x,y-rhs.y);
    }
    double operator *(coor rhs) const //数量积
    {
        return x*rhs.x + y*rhs.y;
    }
};
const double eps = 1e-8;
struct Line
{
    coor point1,point2;
    Line(){}
    Line(coor xx,coor yy):point1(xx),point2(yy){}
    bool operator &(Line rhs) const //判断直线和rhs线段是否相交
    {
        //自己表示一条直线,然而rhs表示的是线段
        //思路,判断rhs线段上两个端点是否在this直线的同一侧即可,用一侧,就不相交
        coor ff1 = point2 - point1; //直线的方向向量
        return ( ((rhs.point1-point1)^ff1) * ((rhs.point2-point1)^ff1) ) <= 0;//符号不同或者有0,证明相交
    }
}a[maxn];
int n;

bool same (double a,double b)
{
    return fabs(a-b)<eps;
}
bool check (coor aa,coor bb)
{
    Line t = Line(aa,bb);
    for (int i=1;i<=n;++i)
    {
        if (!(t&a[i]))
        {
            return false;
        }
    }
    return true;
}
void work ()
{
    scanf("%d",&n);
    for (int i=1;i<=n;++i)
    {
        scanf("%lf%lf%lf%lf",&a[i].point1.x,&a[i].point1.y,&a[i].point2.x,&a[i].point2.y);
    }
    if (n==1)
    {
        printf ("Yes!\n");
        return ;
    }
    for (int i=1;i<=n;++i)
    {
        for (int j=i+1;j<=n;++j)
        {
            if (check(a[i].point1,a[j].point1))
            {
                printf ("Yes!\n");
                return ;
            }
            if (check(a[i].point1,a[j].point2))
            {
                printf ("Yes!\n");
                return ;
            }
            if (check(a[i].point2,a[j].point1))
            {
                printf ("Yes!\n");
                return ;
            }
            if (check(a[i].point2,a[j].point2))
            {
                printf ("Yes!\n");
                return ;
            }
        }
    }
    printf ("No!\n");
    return ;
}

int main()
{
#ifdef local
    freopen("data.txt","r",stdin);
#endif
    int t;
    scanf("%d",&t);
    while(t--) work();
    return 0;
}

时间: 2024-08-05 15:25:51

POJ 3304 Segments 判断直线和线段相交的相关文章

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 2074 /// 判断直线与线段相交 视野盲区

题目大意: 将所有物体抽象成一段横向的线段 给定房子的位置和人行道的位置 接下来给定n个障碍物的位置 位置信息为(x1,x2,y) 即x1-x2的线段 y相同因为是横向的 求最长的能看到整个房子的一段人行道的长度 若不在 y(房子)和y(人行道)之间的 不会有视野的阻碍 注意边界处理 因为盲区可能包含在人行道内 也可能超出 #include <cstdio> #include <algorithm> #include <cmath> using namespace st

hdu 3304(直线与线段相交)

Segments Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12042   Accepted: 3808 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 1039 直线和线段相交

题意: 题意很好理解,从左边射过来的光线,最远能经过管道到右边多少距离. 分析: 光线一定经过一个上端点和一个下端点,这一点很容易想到.然后枚举上下端点即可 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #define eps 1e-8 #define INF 1e9 #define OK sgn(tmp

直线与直线相交 直线与线段相交 线段与线段相交

int sgn(double x) { if(fabs(x) < eps) return 0; return x < 0 ? -1: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 opera

POJ 3304 Segments【叉积】

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

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

http://poj.org/problem?id=3304 等价于是否存在一条直线穿过所有线段 判断直线与线段是否相交: 首先用两点p1,p2确定了一条直线 在用p1,p2分别与计算线段两个端点计算叉乘即可 ,叉乘之积>0就说明线段两端点在直线的同侧,也就是直线不经过此线段 注意顺序不要搞反了 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #incl

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.