线段是否相交 && 线段与直线是否相交 [Segments Poj3304]

题目传送门

计算几何
这题大概的意思就是,给你一系列的线段,问存不存在那么一条直线,当所有的线段向这条直线上投影的时候,投影能够有至少一个交点。

脑洞:投影的事情,我们可以用一条直线来表示方向,表示所有的线段沿着这个直线的某个方向进行投影(投影直线将与这条直线相垂直)。 那么至少有一个交点就变成了,能不能找到一条直线,将所有的线段串在一起?
接下里的任务是找这样的一条直线,这样的直线我们应该从各个线段的端点开始,找边沿的直线。
那么如何判断 这条直线与线段是否相交? 注意,题目给出的是四个点,没有直线的方程。
用向量吧。
在这里插入图片描述
从叉乘的定义来看 可以发现一下结论。我们只要保证那个角度与180度的关系即可。

那么根据题意 只要 这两个叉乘的乘积满足大于esp(1e-8),就是不满足题意的,这里算进了三点共线的情况。

好像这叫一次跨立实验? 那么线段与线段是否相交呢? 那就两次跨立实验就完成了吧。

然后这道题就是 点的枚举和直线的枚举了。

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

#define eps 1e-6
#define len 10010
using namespace std;

struct line{
    double x1, y1, x2, y2;
    line(){}
    line(double _x1, double _y1, double _x2, double _y2):x1(_x1), y1(_y1), x2(_x2) ,y2(_y2){}
};

line l[len];
int n;

double cross(line a, double x, double y){
    return (a.x1 - x) * (a.y2 - y) - (a.x2 - x) * (a.y1 - y);
}

bool check(double x1, double y1, double x2, double y2){
    if ((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) < eps) return false;
    line a(x1, y1, x2, y2);
    for (int i=0; i<n; i++){
        if (cross(a, l[i].x1, l[i].y1) * cross(a, l[i].x2, l[i].y2) > eps) return false;
    }
    return true;
}

int main(){
    int T; scanf ("%d", &T);
    while (T--){
        scanf("%d", &n);
        for (int i=0; i<n; i++)  scanf("%lf%lf%lf%lf", &l[i].x1, &l[i].y1 ,&l[i].x2, &l[i].y2);
        if (n==1) {
            printf("Yes!\n");
            continue;
        }

        bool flag = false;

        for (int i=0; i<n; i++){
            for (int j=i+1; j<n; j++){
                if (check(l[i].x1, l[i].y1, l[j].x1, l[j].y1) ||
                    check(l[i].x1, l[i].y1, l[j].x2, l[j].y2) ||
                    check(l[i].x2, l[i].y2, l[j].x1, l[j].y1) ||
                    check(l[i].x2, l[i].y2, l[j].x2, l[j].y2))
                        flag = true;
                if (flag) break;
            }
            if (flag) break;
        }

        if (flag) printf("Yes!\n");
        else printf("No!\n");
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值