【SGU 128】Snake

128. Snake

time limit per test: 0.5 sec.
memory limit per test: 4096 KB

There are N points given by their coordinates on a plane. All coordinates (xi,yi) are integers in a range from -10000 up to 10000 inclusive . It is necessary to construct a broken line satisfying the following conditions:
1. The broken line should be closed.
2. End points of each segment (verteces) of the broken line can only be the given points, and all given points should be used.
3. Each two consecutive segments of the broken line should form a corner of 90 degrees in each vertex point.
4. The sides of the broken line should be parallel to coordinate axes.
5. The broken line should have no self-crossing and self-contact.
6. The broken line should have the minimal length.
You have to either find the length L of the constructed broken line, or determine that it is impossible to construct such a broken line.

Input

First line contains the number N (4 <= N <= 10000) - amount of points. Each of the following N lines contains coordinates of points separated by space xi and yi (1 <= i <= N). Points are given in random order.

Output

First line should contain the length of the broken line L or 0 if there is no solution.

Sample Input

Sample Output

4
0 0
0 3
3 3
3 0

Sample Output

12

  题目大意是说:
给你N个点,让你用这N个点围城一个闭合的环,交点两边的线段组成90°的角,线段都平行于坐标轴,线段两两不相交,使线段长度和最短。
  
  ----------------------------------------我是分界线---------------------------------------------
 “交点两边的线段组成90°的角”很关键,前面的条件说明了答案的唯一性。
 因为拐角必须为90°,所以在同一平面上的点P1、P2、P3……Pn,连接方法只能是P1-P2,P3-P4……
 所以同一平面上的点的个数一定是偶数个,否则无解。
 然后我们分别以Y轴和X轴为参考连线。
 如何判断相交呢?
 相交只有一种情况:即平行于X轴的线段(x1,y)-(x2,y)和平行与y轴的线段(x,y1)-(x,y2)相交。如果两线段相交,一定符合(x1<x<x2),(y1<y<y2)。
 所以我们可以按X排序之后,判断每一条平行于Y轴的直线是否有一条平行与X轴的直线与之相交。
 这一步,可以线段树,可以树状数组。
 当线段左端点出现时将他插入线段树,右端点出现时删除。
 
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <algorithm>
#define lowbit(x) ((x)&(-x))
using namespace std;
template<class T>inline void gmax(T &a,T b){if(a<b)a=b;}
struct POINT{int x,y;}p[10001];

inline bool cmpX(int a,int b){return p[a].x<p[b].x;}
inline bool cmpY(int a,int b){return p[a].y<p[b].y;}

vector<int> match[10001],pos[20010];
int s[20010],n,maxx=0,ans=0;
bool vis[20010];

void HALT(){
	printf("0\n");
	exit(0);
}

void dfs(int x){
	vis[x]=true;
	for(int i=0;i<2;i++)
		if(!vis[match[x][i]]) dfs(match[x][i]);
}

void Modify(int x,int val){
	for(int i=x;i<=maxx;i+=lowbit(i)) s[i]+=val;
}

int Query(int x){
	int sum=0;
	for(int i=x;i>0;i-=lowbit(i)) sum+=s[i];
	return sum;
}
	
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d",&p[i].x,&p[i].y);
		p[i].x+=10001,p[i].y+=10001;
		gmax(maxx,p[i].x);
		gmax(maxx,p[i].y);
	}
	for(int i=1;i<=n;i++) pos[p[i].x].push_back(i);
	for(int i=1;i<=maxx;i++)
		if(pos[i].size()%2) HALT();
		else if(pos[i].size()){
			vector<int> &tmp=pos[i];
			sort(tmp.begin(),tmp.end(),cmpY);
			for(int j=0;j<tmp.size();j+=2){
				ans+=p[tmp[j+1]].y-p[tmp[j]].y;
				match[tmp[j]].push_back(tmp[j+1]);
				match[tmp[j+1]].push_back(tmp[j]);
			}
			tmp.clear();
		}
	for(int i=1;i<=n;i++) pos[p[i].y].push_back(i);
	for(int i=1;i<=maxx;i++)
		if(pos[i].size()%2) HALT();
		else if(pos[i].size()){
			vector<int> &tmp=pos[i];
			sort(tmp.begin(),tmp.end(),cmpX);
			for(int j=0;j<tmp.size();j+=2){
				ans+=p[tmp[j+1]].x-p[tmp[j]].x;
				match[tmp[j]].push_back(tmp[j+1]);
				match[tmp[j+1]].push_back(tmp[j]);
			}
		}
	for(int i=1;i<=n;i++)
		if(match[i].size()!=2) HALT();
	dfs(1);
	for(int i=1;i<=n;i++)
		if(!vis[i]) HALT();
	memset(vis,false,sizeof(vis));
	for(int i=1;i<=maxx;i++)
		if(pos[i].size()){
			vector<int> &tmp=pos[i];
			for(int j=0;j<tmp.size();j+=2){
				int x1=p[tmp[j]].x,x2=p[tmp[j+1]].x;
				if(x1+1<x2 && (Query(x2-1)-Query(x1))) HALT();
				if(vis[x1]) Modify(x1,-1);
				else Modify(x1,1);
				if(vis[x2]) Modify(x2,-1);
				else Modify(x2,1);
				vis[x1]=!vis[x1];vis[x2]=!vis[x2];
			}
		}
	printf("%d\n",ans);
	return 0;
}

posted @ 2011-08-15 18:45  Delostik  阅读(416)  评论(0编辑  收藏  举报