POJ:1127-Jack Straws(线段求交点模板)

本文介绍了一种解决线段交点问题的算法,通过向量表示线段并利用向量运算求解交点,同时使用并查集处理线段交的传递性,适用于多个线段相交情况的判断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://poj.org/problem?id=1127

题意:给你n个线段,每个线段给你两个端点的坐标。然后随意问你两个线段是否相交,线段交可以传递。

解题心得:一个线段可以用向量表示,然后用向量求交的方法得到交点,再判断交点是否在两个线段上。当两个线段平行时直接判断两个线段的端点是否在另一个线段上。

#include <cstring>
#include <stdio.h>
using namespace std;
const int maxn = 200;
const double eps = 1e-10;

double abs(double x) {//abs出问题了,哭死,重载之后就过了
    if(x < 0)
        return -x;
    return x;
}

double add(double a, double b) {//考虑误差的加法运算
    if(abs(a + b) < eps * (abs(a) + abs(b))) return 0;
    return a + b;
}

struct P {
    double x, y;

    P () {}

    P(double x, double y) : x(x), y(y) {}

    //重载点对间的操作符
    P operator + (P p) {
        return P(add(x, p.x), add(y, p.y));
    }

    P operator - (P p) {
        return P(add(x, -p.x), add(y, -p.y));
    }

    P operator * (double d) {
        return P(x*d, y*d);
    }

    double dot(P p) {//向量点乘
        return add(x*p.x, y*p.y);
    }

    double det(P p) {//向量叉乘
        return add(x*p.y, -y*p.x);
    }
};

bool on_seg(P p1, P p2, P q) {//判断q是否在p1,p2之间
    return (p1 - q).det(p2 - q) == 0 && (p1 - q).dot(p2 - q) <= 0;
}

P intersection(P p1, P p2, P q1, P q2) {//得到p2-p1向量和q1-q2的交点坐标
    return p1 + (p2 - p1) * ((q2 - q1).det(q1 - p1) / (q2 - q1).det(p2 - p1));
}

P q[maxn], p[maxn];//p记录线段左边的坐标,q记录线段右边的坐标

//并查集用来检查线段交的传递
int father[maxn];

int find(int x) {
    if(father[x] == x) return x;
    else return father[x] = find(father[x]);
}

void merge(int x,int y) {
    int fx = find(x);
    int fy = find(y);

    if(fx != fy) father[fx] = fy;
}

int main() {
//    freopen("1.in", "r", stdin);
    int n;
    while(scanf("%d", &n)!= EOF && n) {
        for(int i=1;i<=n;i++) {
            scanf("%lf%lf%lf%lf", &p[i].x, &p[i].y, &q[i].x, &q[i].y);
            father[i] = i;
        }

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j < i; j++) {
                if ((p[i] - q[i]).det(p[j] - q[j]) == 0) {//如果两个线段平行
                    if (on_seg(p[i], q[i], p[j])//如果两个线段在平行的时候又重叠的部分
                        || on_seg(p[i], q[i], q[j])
                        || on_seg(p[j], q[j], p[i])
                        || on_seg(p[j], q[j], q[i])) {
                        merge(i, j);
                    }
                } else {

                    P r = intersection(p[i], q[i], p[j], q[j]);//得到两个向量的交点
                    if (on_seg(p[i], q[i], r) && on_seg(p[j], q[j], r))//查看这个交点是否在两个线段上
                        merge(i, j);
                }
            }
        }

        int a, b;
        while (scanf("%d%d", &a, &b) && a + b) {
            if (find(a) == find(b)) puts("CONNECTED");
            else puts("NOT CONNECTED");
        }
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值