Cycling Roads URAL 1966 线段相交 + 并查集
2017-08-03 17:33
393 查看
题目:https://vjudge.net/problem/URAL-1966
题意:给出n个点的坐标,并标号为1~n,给出m条线段,线段端点即为标号为1~n的点。判断是否所有点连通,两线段只要有公共点即互相连通。
思路:用叉积判断线段相交,把所有直接连通的点所在集合合并,顺便统计集合数量,最终只剩一个集合就连通。
注意有种情况,把我坑的不轻。数据里有孤立点位于一条线段上的情况,我本以为只要把各种线段相交情况考虑到就行,但还需要单独扫一遍点在线段上的情况。
训练赛的时候用高中解析几何的知识做了两道几何题,另外一道AC了,这道考虑了各种情况也没AC,赛后想想不能一直用高中知识做几何,算坐标考虑斜率不存在的情况就能难受死,于是对着刘汝佳的算法竞赛入门经典训练指南的第四章几何部分学了一下二维几何基础,重新写了一遍然而依旧一直WA,最后发现卡在之前说的坑上。不过好歹几何稍微入了个门。
代码:c++
题意:给出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 = b155 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; }
相关文章推荐
- URAL 1966 Cycling Roads 点在线段上、线段是否相交、并查集
- URAL - 1966 - Cycling Roads(并查集 + 判线段相交)
- hdu 1558 判断线段相交 + 并查集
- hdu 1558(线段相交+并查集)
- hdu 1588 线段相交+并查集
- POJ - 1127 Jack Straws(线段相交/并查集)
- 第五次个人赛D题 Segment set 判断线段相交+并查集
- hdu1558线段相交与并查集
- HDU 1558 Segment set 并查集 线段相交
- POJ 1127 Jack Straws(线段相交判断+并查集)
- HDU-1558,Segment set,并查集+线段相交模拟
- 【计算几何初步-线段相交+并查集】【HDU1558】Segment set
- hdu 1558 Segment set 线段相交+并查集
- HDU 1558 判断两个线段相交附带并查集
- hdu 1558 Segment set(线段相交+并查集)
- URAL - 1966 - Cycling Roads(并检查集合 + 判刑线相交)
- poj 1127 判断任意两线段是否相交,叉积+floyd(并查集)@
- 判断线段相交(hdu1558 Segment set 线段相交+并查集)
- HDOJ1558 线段相交问题+并查集处理
- ccsu1359 木棒相交 (叉积线段判交,并查集判断是否属于同一个集合)