zoukankan      html  css  js  c++  java
  • 【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;
    }
    

  • 相关阅读:
    找出优先要作的工作
    我要作技术研发了
    确定配色方案
    今天公司搬家
    要作界面原型了
    使用自已的命名空间
    进行审核了
    那里有皮肤软件工开发包的源码???
    发葡萄
    作业务规则挺难
  • 原文地址:https://www.cnblogs.com/Delostik/p/2139753.html
Copyright © 2011-2022 走看看