zoukankan      html  css  js  c++  java
  • Snake

    题目大意:有N个点,如果可以使用这N个点连接,连接的时候任意两条边要成直角,任意边都要平行于x轴或者y轴,并且不能出现跨立相交,最终组成一个闭合的多边形,求出来这个多边形的最小长度。

    分析:容易证明这个多边形的存在是唯一的,因为每个点出发都会产生两条边,横着的或者竖着的,而且,相同x或者相同y的点所在的线上的点数要是偶数,否则无法分配,首先按照x点的值进行排序,那么就会得到平行于y轴的边,并且把这些相同的x值加入它所在的集合,用来判断与横轴的相交(可以使用二分查找的方式快速判断是否有相交边),然后按照y值排序得到平行于x轴的边,判断是否有相交情况即可,可以使用并查集判断图是否联通。

    ps.错了N次,才发现原来做去重的时候没有排序.........,判断相交的时候也可以使用线段树,不过感觉略麻烦

    代码如下:

    ====================================================================================================================================================

    #include<stdio.h>
    #include<algorithm>
    #include<string.h>
    #include<vector>
    using namespace std;
    
    const int MAXN = 20007;
    
    struct point{int x, y, id;}p[MAXN];
    struct segment{
        point s, e;
        segment(){}
        segment(point s, point e):s(s),e(e){}
    };
    vector<segment>sg[MAXN];
    int Hash[MAXN], Hn, father[MAXN];
    
    bool cmp_point_x(point t1, point t2)
    {
        if(t1.x != t2.x)
            return t1.x < t2.x;
        return t1.y < t2.y;
    }
    bool cmp_point_y(point t1, point t2)
    {
        if(t1.y != t2.y)
            return t1.y < t2.y;
        return t1.x < t2.x;
    }
    bool QuickPow(int k, int e)
    {
        int L=0, R = sg[k].size()-1;
    
        while(L <= R)
        {
            int Mid = (L+R) >> 1;
            segment t = sg[k][Mid];
    
            if(e > t.s.y && e < t.e.y)
                return true;
            if(e < t.s.y)
                R = Mid - 1;
            else
                L = Mid + 1;
        }
    
        return false;
    }
    int Find(int x)
    {
        if(x != father[x])
            father[x] = Find(father[x]);
        return father[x];
    }
    void Union(int u, int v)
    {
        u = Find(u), v = Find(v);
        father[u] = v;
    }
    int main()
    {
        int N, ok=0, len=0;
    
        scanf("%d", &N);
    
        for(int i=0; i<N; i++)
        {
            scanf("%d%d", &p[i].x, &p[i].y);
            p[i].id = i;
            Hash[i] = p[i].x;
            father[i] = i;
        }
    
        sort(p, p+N, cmp_point_x);///先按照x点进行排序
        sort(Hash, Hash+N);
        Hn = unique(Hash, Hash+N) - Hash;
    
        for(int i=0; i<N; i+=2)
        {
            if(i==N-1 || p[i].x  != p[i+1].x)
            {
                ok = 1;
                break;
            }
    
            int k = lower_bound(Hash, Hash+Hn, p[i].x) - Hash;
            sg[k].push_back(segment(p[i],p[i+1]));
            Union(p[i].id, p[i+1].id);
            len += p[i+1].y - p[i].y;
        }
    
        if(ok)
        {///分列不成功
            printf("0
    ");
            return 0;
        }
    
        sort(p, p+N, cmp_point_y);
    
        for(int i=0; i<N; i+=2)
        {
            if(i==N-1 || p[i].y != p[i+1].y)
            {
                ok = 1;
                break;
            }
            Union(p[i].id, p[i+1].id);
            len += p[i+1].x - p[i].x;
    
            int L = lower_bound(Hash, Hash+Hn, p[i].x) - Hash;
            int R = lower_bound(Hash, Hash+Hn, p[i+1].x) - Hash;
    
            for(int j=L+1; j<R; j++)
            {
                ok = QuickPow(j, p[i].y);
                if(ok)break;
            }
    
            if(ok)break;
        }
    
        int cnt = 0;
        for(int i=0; i<N; i++)
        {
            if(father[i] == i)
                cnt++;
            if(cnt > 1)
            {
                ok = 1;
                break;
            }
        }
    
        if(ok)
            printf("0
    ");
        else
            printf("%d
    ", len);
    
        return 0;
    }
  • 相关阅读:
    五种常见的 PHP 设计模式(收藏)
    写年度工作总结
    关于window.open和window.showdialog返回值的问题
    50个令人叹为观止的JavaScript应用站点[转]
    10大免费FLV播放器下载[转]
    6个去掉图片上的文字的技巧实用简单
    mysql命令大全(转)
    10款替代Windows Media Player的播放器
    Editplus FTP远程访问Ubuntu
    C++ 元编程 Meta Programming
  • 原文地址:https://www.cnblogs.com/liuxin13/p/4837080.html
Copyright © 2011-2022 走看看