HDU 1086 (平面几何 线段求交)

题目链接:点击这里

题意:求n条线段的所有交点个数. 题目保证线段不会有重合部分.

直接求交点, 把所有的交点扔进一个集合统计一下就行了.

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
#include <set>
using namespace std;

const double eps = 1e-8;
const double INF = 1e20;
const double pi = acos (-1.0);

int dcmp (double x) {
    if (fabs (x) < eps) return 0;
    return (x < 0 ? -1 : 1);
}
inline double sqr (double x) {return x*x;}

//*************点
struct Point {
    double x, y;
    Point (double _x = 0, double _y = 0):x(_x), y(_y) {}
    void input () {scanf ("%lf%lf", &x, &y);}
    void output () {printf ("%.2f %.2f\n", x, y);}
    bool operator == (const Point &b) const {
        return (dcmp (x-b.x) == 0 && dcmp (y-b.y) == 0);
    }
    bool operator < (const Point &b) const {
        return (dcmp (x-b.x) == 0 ? dcmp (y-b.y) < 0 : x < b.x);
    }
    Point operator + (const Point &b) const {
        return Point (x+b.x, y+b.y);
    }
    Point operator - (const Point &b) const {
        return Point (x-b.x, y-b.y);
    }
    Point operator * (double a) {
        return Point (x*a, y*a);
    }
    Point operator / (double a) {
        return Point (x/a, y/a);
    }
    double len2 () {//返回长度的平方
        return sqr (x) + sqr (y);
    }
    double len () {//返回长度
        return sqrt (len2 ());
    }
    Point change_len (double r) {//转化为长度为r的向量
        double l = len ();
        if (dcmp (l) == 0) return *this;//零向量返回自身
        r /= l;
        return Point (x*r, y*r);
    }
    Point rotate_left () {//顺时针旋转90度
        return Point (-y, x);
    }
    Point rotate_right () {//逆时针旋转90度
        return Point (y, -x);
    }
    Point rotate (Point p, double ang) {//绕点p逆时针旋转ang
        Point v = (*this)-p;
        double c = cos (ang), s = sin (ang);
        return Point (p.x + v.x*c - v.y*s, p.y + v.x*s + v.y*c);
    }
    Point normal () {//单位法向量
        double l = len ();
        return Point (-y/l, x/l);
    }
};

double cross (Point a, Point b) {//叉积

    return a.x*b.y-a.y*b.x;
}
double dot (Point a, Point b) {//点积

    return a.x*b.x + a.y*b.y;
}
double dis (Point a, Point b) {//两个点的距离

    Point p = b-a; return p.len ();
}
double rad_degree (double rad) {//弧度转化为角度

    return rad/pi*180;
}
double rad (Point a, Point b) {//两个向量的夹角

    return fabs (atan2 (fabs (cross (a, b)), dot (a, b)) );
}
bool parallel (Point a, Point b) {//向量平行
    double p = rad (a, b);
    return dcmp (p) == 0 || dcmp (p-pi) == 0;
}

//************直线 线段
struct Line {
    Point s, e;//直线的两个点
    Line () {}
    Line (Point _s, Point _e) : s(_s), e(_e) {}
    //一个点和倾斜角确定直线
    Line (Point p, double ang) {
        s = p;
        if (dcmp (ang-pi/2) == 0) {
            e = s + Point (0, 1);
        }
        else
            e = s + Point (1, tan (ang));
    }
    //ax+by+c=0确定直线
    Line (double a, double b, double c) {
        if (dcmp (a) == 0) {
            s = Point (0, -c/b);
            e = Point (1, -c/b);
        }
        else if (dcmp (b) == 0) {
            s = Point (-c/a, 0);
            e = Point (-c/a, 1);
        }
        else {
            s = Point (0, -c/b);
            e = Point (1, (-c-a)/b);
        }
    }
    void input () {
        s.input ();
        e.input ();
    }
    void adjust () {
        if (e < s) swap (e, s);
    }
    double length () {//求线段长度
        return dis (s, e);
    }
    double angle () {//直线的倾斜角
        double k = atan2 (e.y-s.y, e.x-s.x);
        if (dcmp (k) < 0) k += pi;
        if (dcmp (k-pi) == 0) k -= pi;
        return k;
    }
};

int relation (Point p, Line l) {//点和直线的关系
    //1:在左侧 2:在右侧 3:在直线上
    int c = dcmp (cross (p-l.s, l.e-l.s));
    if (c < 0) return 1;
    else if (c > 0) return 2;
    else return 3;
}

bool point_on_seg (Point p, Line l) {//判断点在线段上
    return dcmp (cross (p-l.s, l.e-l.s)) == 0 &&
    dcmp (dot (p-l.s, p-l.e) <= 0);
    //如果忽略端点交点改成小于号就好了
}

bool parallel (Line a, Line b) {//直线平行
    return parallel (a.e-a.s, b.e-b.s);
}

int seg_cross_seg (Line a, Line v) {//线段相交判断
    //2:规范相交 1:不规范相交 0:不相交
    int d1 = dcmp (cross (a.e-a.s, v.s-a.s));
    int d2 = dcmp (cross (a.e-a.s, v.e-a.s));
    int d3 = dcmp (cross (v.e-v.s, a.s-v.s));
    int d4 = dcmp (cross (v.e-v.s, a.e-v.s));
    if ((d1^d2) == -2 && (d3^d4) == -2) return 2;
    return (d1 == 0 && dcmp (dot (v.s-a.s, v.s-a.e)) <= 0) ||
        (d2 == 0 && dcmp (dot (v.e-a.s, v.e-a.e)) <= 0) ||
        (d3 == 0 && dcmp (dot (a.s-v.s, a.s-v.e)) <= 0) ||
        (d4 == 0 && dcmp (dot (a.e-v.s, a.e-v.e)) <= 0);
}

int line_cross_seg (Line a, Line v) {//直线和线段相交判断
    //1:规范相交 2:非规范相交 3:不相交
    int d1 = dcmp (cross (a.e-a.s, v.s-a.s));
    int d2 = dcmp (cross (a.e-a.s, v.e-a.s));
    if (d1^d2 == -2) return 2;
    return (d1 == 0 || d2 == 0);
}

int line_cross_line (Line a, Line v) {//直线相交判断
    //0:平行 1:重合 2:相交
    if (parallel (a, v)) return relation (a.e, v) == 3;
    return 2;
}

Point line_intersection (Line a, Line v) {//直线交点
    //调用前确保有交点
    double a1 = cross (v.e-v.s, a.s-v.s);
    double a2 = cross (v.e-v.s, a.e-v.s);
    return Point ((a.s.x*a2-a.e.x*a1)/(a2-a1), (a.s.y*a2-a.e.y*a1)/(a2-a1));
}

int seg_intersectiong (Line a, Line b, Point &p) {//求线段交点
    //0:没有交点 1:规范相交 2:非规范相交
    //调用前确包只有一个交点
    int rel = seg_cross_seg (a, b);
    if (rel == 0) return 0;
    int cnt = 0;
    if (rel == 1) {
        if (point_on_seg (a.e, b)) p = a.e, cnt++;
        if (point_on_seg (a.s, b)) p = a.s, cnt++;
        if (point_on_seg (b.e, a)) p = b.e, cnt++;
        if (point_on_seg (b.s, a)) p = b.s, cnt++;
        return 2;
    }
    p = line_intersection (a, b);
    return 1;
}

double point_to_line (Point p, Line a) {//点到直线的距离
    return fabs (cross (p-a.s, a.e-a.s) / a.length ());
}

double point_to_seg (Point p, Line a) {//点到线段的距离
    if (dcmp (dot (p-a.s, a.e-a.s)) < 0 || dcmp (dot (p-a.e, a.s-a.e)) < 0)
        return min (dis (p, a.e), dis (p, a.s));
    return point_to_line (p, a);
}

Point projection (Point p, Line a) {//点在直线上的投影
    return a.s + (((a.e-a.s) * dot (a.e-a.s, p-a.s)) / (a.e-a.s).len2() );
}

Point symmetry (Point p, Line a) {//点关于直线的对称点
    Point q = projection (p, a);
    return Point (2*q.x-p.x, 2*q.y-p.y);
}

#define maxn 111
int n;
Line l[maxn];
set <Point> gg;

int main () {
    while (cin >> n && n) {
        gg.clear ();
        for (int i = 0; i < n; i++) {
            l[i].input ();
        }
        int ans = 0;
        Point p;
        for (int i = 0; i < n; i++) {
            for (int j = i+1; j < n; j++) {
                if (seg_intersectiong (l[i], l[j], p)) {
                    gg.insert (p);
                }
            }
        }
        cout << gg.size () << "\n";
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值