题目大意:有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; }