题目大意:有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 = ; 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=, R = sg[k].size()-; while(L <= R)
{
int Mid = (L+R) >> ;
segment t = sg[k][Mid]; if(e > t.s.y && e < t.e.y)
return true;
if(e < t.s.y)
R = Mid - ;
else
L = Mid + ;
} 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=, len=; scanf("%d", &N); for(int i=; 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=; i<N; i+=)
{
if(i==N- || p[i].x != p[i+].x)
{
ok = ;
break;
} int k = lower_bound(Hash, Hash+Hn, p[i].x) - Hash;
sg[k].push_back(segment(p[i],p[i+]));
Union(p[i].id, p[i+].id);
len += p[i+].y - p[i].y;
} if(ok)
{///分列不成功
printf("0\n");
return ;
} sort(p, p+N, cmp_point_y); for(int i=; i<N; i+=)
{
if(i==N- || p[i].y != p[i+].y)
{
ok = ;
break;
}
Union(p[i].id, p[i+].id);
len += p[i+].x - p[i].x; int L = lower_bound(Hash, Hash+Hn, p[i].x) - Hash;
int R = lower_bound(Hash, Hash+Hn, p[i+].x) - Hash; for(int j=L+; j<R; j++)
{
ok = QuickPow(j, p[i].y);
if(ok)break;
} if(ok)break;
} int cnt = ;
for(int i=; i<N; i++)
{
if(father[i] == i)
cnt++;
if(cnt > )
{
ok = ;
break;
}
} if(ok)
printf("0\n");
else
printf("%d\n", len); return ;
}