Cycling Roads URAL 1966 线段相交 + 并查集

来源:互联网 发布:贵州旅游大数据报告 编辑:程序博客网 时间:2024/05/18 02:12

题目:https://vjudge.net/problem/URAL-1966

题意:给出n个点的坐标,并标号为1~n,给出m条线段,线段端点即为标号为1~n的点。判断是否所有点连通,两线段只要有公共点即互相连通。

思路:用叉积判断线段相交,把所有直接连通的点所在集合合并,顺便统计集合数量,最终只剩一个集合就连通。
注意有种情况,把我坑的不轻。数据里有孤立点位于一条线段上的情况,我本以为只要把各种线段相交情况考虑到就行,但还需要单独扫一遍点在线段上的情况。

训练赛的时候用高中解析几何的知识做了两道几何题,另外一道AC了,这道考虑了各种情况也没AC,赛后想想不能一直用高中知识做几何,算坐标考虑斜率不存在的情况就能难受死,于是对着刘汝佳的算法竞赛入门经典训练指南的第四章几何部分学了一下二维几何基础,重新写了一遍然而依旧一直WA,最后发现卡在之前说的坑上。不过好歹几何稍微入了个门。

代码:c++

#include <iostream>#include <cstdio>#include <cmath>#include <map>#include <vector>#include <algorithm>#include <cstring>#include <cstdlib>using namespace std;const double esp = 1e-10;const int maxn = 300;int dcmp(double a){    if (fabs(a) < esp)        return 0;    else        return a < 0 ? -1 : 1;}struct Point{    int id;    double x, y;    Point(double xx = 0, double yy = 0, int idx = 0) : x(xx), y(yy), id(idx) {}    bool operator == (Point p)    {        return dcmp(x - p.x) == 0 && dcmp(y - p.y) == 0;    }};typedef Point Vector;Point points[maxn];Vector operator - (Point A, Point B){    return Vector(A.x - B.x, A.y - B.y);}Vector operator + (Vector A, Vector B){    return Vector(A.x + B.x, A.y + B.y);}double Cross(Vector A, Vector B){    return A.x * B.y - A.y * B.x;}double Dot(Vector A, Vector B){    return A.x * B.x + A.y * B.y;}struct Line{    Point v1, v2;    Line(Point p1 = Point(), Point p2 = Point()) : v1(p1), v2(p2) {}};Line lines[maxn];//判断点在线段上bool OnLine(Point p, Line l){    return dcmp(Cross(l.v1 - p, l.v2 - p)) == 0 && dcmp(Dot(l.v1 - p, l.v2 - p)) <= 0;}//判断两线段相交bool LineIntersection(Line l1, Line l2){    if (OnLine(l1.v1, l2) || OnLine(l1.v2, l2) || OnLine(l2.v1, l1) || OnLine(l2.v2, l1))    {        return true;    }    double c1 = Cross(l1.v1 - l2.v1, l1.v1 - l1.v2);    double c2 = Cross(l1.v1 - l2.v2, l1.v1 - l1.v2);    double c3 = Cross(l2.v1 - l1.v1, l2.v1 - l2.v2);    double c4 = Cross(l2.v1 - l1.v2, l2.v1 - l2.v2);    return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0;}int fa[maxn];int n, m;int setamount;//并查集的各种函数void init(){    setamount = n;    for (int i = 1; i <= n; i++)    {        fa[i] = i;    }}int setfind(int u){    return fa[u] == u ? u : fa[u] = setfind(fa[u]);}bool check(int a, int b){    return setfind(a) == setfind(b);}void setunion(int a, int b){    int p1 = setfind(a);    int p2 = setfind(b);    if (p1 != p2)    {        fa[p1] = p2;        setamount--;    }}int main(){    scanf("%d%d", &n, &m);    init();    for (int i = 1; i <= n; i++)    {        double x, y;        scanf("%lf%lf", &x, &y);        points[i] = Point(x, y, i);    }    for (int i = 1; i <= m; i++)    {        int a, b;        scanf("%d%d", &a, &b);        lines[i] = Line(points[a], points[b]);        if (!check(a, b))        {            setunion(a, b);        }        for (int j = 1; j <= n; j++)        {            if (OnLine(points[j], lines[i]))            {                setunion(j, a);            }        }        for (int j = 1; j < i; j++)        {            if (LineIntersection(lines[i], lines[j]))            {                setunion(lines[i].v1.id, lines[j].v1.id);                setunion(lines[i].v2.id, lines[j].v1.id);                setunion(lines[i].v1.id, lines[j].v2.id);                setunion(lines[i].v2.id, lines[j].v2.id);            }        }    }    printf("%s", setamount == 1 ? "YES" : "NO");    return 0;}
原创粉丝点击