Timus Online Judge 1966 Cycling Roads

来源:互联网 发布:淘宝宝贝视频制作 编辑:程序博客网 时间:2024/06/08 15:12

再一次对timus感到无力,这道题目是放在Graph Theory Problems里,却感觉和Graph Theory没有毛关系。明明是个计算几何嘛。

题目大意:Vova在深圳骑自行车逛公园,公园里有N处景点,给出N个景点的坐标,然后再给出M条为线段的边。若两条线段有公共点,那么这两条线段的四个端点中的任意一个都能到达其余三个。问Vova是否能从一个点出发,到达其余所有的景点。N和M的最大值都是200,每个景点的坐标的x和y的绝对值是小于等于30000的。

当看到这道题目的时候,也许会有很多人会想到用某种生成树的算法来解决,确实是这样的,假如所有点都在一棵生成树上,那么答案就是“YES”。所以,我们可以直接用并查集来维护,当所有的点都在一个集合内的时候我们就输出“YES”,否则答案就“NO”。我们可以将每条边的两个端点所在的集合先给合并,然后判断两条线段是否相交,若相交,就把两条线段所在的集合合并成一个集合。还有就是得考虑出现单点的情况,若某一个点在某一条线段上,我们就要合并这个点所在集合和这条线段所在的集合。最后判断一下总共有多少个集合就可以了。

其中, 判断线段相交用叉积,我想这个没什么好说的吧,需要注意的是坐标范围是-30000~30000,那么计算叉积的时候中间爆long long的情况,注意处理一下就可以了,反正我是在这里WA两次。

这段代码我调试了很久,原因是把main写成了mian,编译一直不能通过,报了一个看不懂的error,感到莫名其妙的,还以为是自己的编译器哪里文件被删掉了,还找别人帮我编译,实在是羞愧,还好吃饭的时候在手机上看代码看到了这个“mian”!!!

Show me the code!

#include <iostream>#include <vector>#define ll long long#define pll pair<ll, ll>#define pii pair<int, int>#define x first#define y secondusing namespace std;vector<pii> vec(201), edge;vector<int> fa(201);ll turn(ll a) {//因为叉积的结果只需要正负,所以,为了避免报long long,这里需要转换一下    if (a == 0) return 0;    return a > 0 ? 1 : -1;}ll CrossProduct(pll a, pll b, pll c) {//判断点C在线段ab的左边还是右边    pll ab(b.x - a.x, b.y - a.y), ac(c.x - a.x, c.y - a.y);    return turn(ab.x * ac.y - ab.y * ac.x);//abc三点共线是结果为0,c在ab左边的时候结果小于0,否则大于0}bool is_intersection(pll a, pll b, pll c, pll d) {//判断线段ab和cd是否有公共点    ll res_ab = CrossProduct(a, b, c) * CrossProduct(a, b, d);    ll res_cd = CrossProduct(c, d, a) * CrossProduct(c, d, b);    return res_ab < 0 && res_cd < 0;}int find(int x) {    return fa[x] = fa[x] == x ? x : find(fa[x]);}void unite(int x, int y) {    int fx = find(x), fy = find(y);    fa[fy] = fx;}bool solve(int N) {    for (int i = 1; i <= N; ++i) fa[i] = i;    for (int i = 0; i < edge.size(); ++i) {        unite(edge[i].x, edge[i].y);//合并同一线段的两个端点所在的集合        for (int j = i + 1; j < edge.size(); ++j) {            unite(edge[j].x, edge[j].y);//合并同一线段的两个端点所在的集合            if (is_intersection(vec[edge[i].x], vec[edge[i].y],                vec[edge[j].x], vec[edge[j].y])) {//若两条线段有公共点,那么就合并两条线段所在的集合                unite(edge[i].x, edge[j].x);            }        }    }    for (int i = 0; i < edge.size(); ++i) {        for (int j = 1; j <= N; ++j) {            pll a = vec[edge[i].x], b = vec[edge[i].y], c = vec[j];            int minx = min(a.x, b.x), maxx = max(a.x, b.x),                miny = min(a.y, b.y), maxy = max(a.y, b.y);            if (CrossProduct(a, b, c) == 0 &&                minx <= c.x && c.x <= maxx &&                miny <= c.y && c.y <= maxy) {//判断单点是否在这条线段上,若是,则合并单点所在的结合和这条线段所在集合                unite(edge[i].x, j);            }        }    }    int f1 = find(1);    for (int i = 2; i <= N; ++i) {//计算集合的个数        if (find(i) != f1) return false;    }    return true;}int main() {    int N, M;    cin >> N >> M;    for (int i = 1; i <= N; ++i) cin >> vec[i].x >> vec[i].y;    for (int i = 0; i < M; ++i) {        int u, v;        cin >> u >> v;        edge.push_back(pll(u, v));    }    cout << (solve(N) ? "YES" : "NO") << endl;    return 0;}
0 1
原创粉丝点击