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;
}
原文地址:https://www.cnblogs.com/liuxin13/p/4837080.html