<传送门>

128. Snake

time limit per test: 0.25 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个点构造一个闭合图形,这个图形要满足以下条件:

1.这个图形要是闭合的;
2.图形上的点只能是给定的点,且每个点只能用一次;
3.每个顶点相连的两条边必须互相垂直;
4.每条边都要平行于坐标轴;
5.每条线除了顶点外都不能互相相交;
6.闭合图形的周长要最小;

N-----点的个数
接下来N个点。
如果存在则输出最小长度;否则输出0。

题目意思很easy,但是实现的时候要考虑很多小细节,和队友两个人讨论了一天,感觉代码实现的能力还是短板,需要加强。

【题目分析】

1.首先,点的个数必须是偶数,这样才能满足每个点相连的两条边都是90度的条件;

2. 同一个x值或同一个y值只能对应偶数个坐标;

3.对于像a(x1,y),b(x2,y),c(x3,y),d(x4,y)类型的,只能是跳跃的连接,即:a-b,c-d;

4.根据题给的前四个条件,可以知道这个多边形一定是唯一的,所以就省去了找最有多边形的麻烦;

接下来就是判断是否能够用所有点来实现一个闭合曲线的问题了:

1.只能有一个连通分支;------------------------并查集or深搜

2.不能出现两边相交(除给定的点外)-------------暴力or线段树

对于判断连通分支的话肯定是并查集好一点,一开始我用dfs做了,感觉建图就卡了老半天。

2.判断是否相交的情况:线段树当然是首选,但是这题暴力也能60ms水过,我就不说什么了。

一开始代码写残了,分析了各种图形,什么“回”字形,“T”字形,“8”字形分析了一大堆,代码各种打补丁。最后还是得全部删了重写。

//Memory   Time
// 1726K 63MS
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<iomanip>
#include<string>
#include<cmath>
#include<bits/stdc++.h>
#define LL __int64
#define MAX 10010
#define exit {puts("0"); return 0;}
using namespace std;
int N;
int father[MAX];
int Hx,Sx;
struct Node
{
int x,y,id;
};
Node node[MAX];
struct edge
{
Node s,e;
};
edge hx[3*MAX],sx[3*MAX];
void read()
{
cin>>N;
for(int i=1;i<=N;i++)
{
cin>>node[i].x>>node[i].y;
node[i].id=i;
father[i]=i;
}
} bool cmp1(Node a,Node b)
{
if(a.y==b.y)
return a.x<b.x;
else return a.y<b.y;
}
bool cmp2(Node a,Node b)
{
if(a.x==b.x)
return a.y<b.y;
else return a.x<b.x;
} int find(int x)
{
return father[x] == x ? x : father[x] = find(father[x]);
} bool build_hx_edge()
{
sort(node+1,node+1+N,cmp2);
for(int i=1;i<N;i+=2)
{
if((node[i].x!=node[i+1].x)||(node[i].y==node[i+1].y))
return 0;
hx[Hx].s=node[i];
hx[Hx].e=node[i+1];
Hx++;
int x=find(node[i].id);
int y=find(node[i+1].id);
if(x!=y)
father[x]=y;
}
return 1;
} bool build_sx_edge()
{
sort(node+1,node+1+N,cmp1);
for(int i=1;i<N;i+=2)
{
if((node[i].y!=node[i+1].y)||(node[i].x==node[i+1].x))
return 0;
sx[Sx].s=node[i];
sx[Sx].e=node[i+1];
Sx++;
int x=find(node[i].id);
int y=find(node[i+1].id);
if(x!=y)
father[x]=y;
}
return 1;
} bool Is_connect()
{
int tp=find(1);
for(int i=2;i<=N;i++)
if(find(i)!=tp)
return 0;
return 1;
} bool judge()
{
for(int i=0;i<Hx;i++)
for(int j=0;j<Sx;j++)
if(sx[j].s.x < hx[i].s.x && hx[i].s.x < sx[j].e.x&& hx[i].s.y < sx[j].s.y && sx[j].s.y < hx[i].e.y)
return 0;
return 1;
} int calcu()
{
int ans=0;
for(int i=0;i<Hx;i++)
ans+=hx[i].e.y-hx[i].s.y;
for(int i=0;i<Sx;i++)
ans+=sx[i].e.x-sx[i].s.x;
return ans;
} int main()
{
// freopen("cin.txt","r",stdin);
// freopen("cout.txt","w",stdout);
read(); if(N==0)
exit if(!build_hx_edge()) //构造横边
exit if(!build_sx_edge()) //构造竖边
exit if(!Is_connect())
exit if(!judge())
exit
cout<<calcu()<<endl;
return 0;
}

  

SGU 128. Snake --- 暴力枚举+并查集+贪心+计算几何的更多相关文章

  1. HDU 1598 find the most comfortable road 并查集+贪心

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1598 find the most comfortable road Time Limit: 1000 ...

  2. [POJ2054]Color a Tree (并查集+贪心)

    POJ终于修好啦 题意 和UVA1205是同一题,在洛谷上是紫题 有一棵树,需要给其所有节点染色,每个点染色所需的时间是一样的都是11.给每个点染色,还有一个开销“当前时间×ci×ci”,cici是每 ...

  3. Codeforces Round #383 (Div. 2) A,B,C,D 循环节,标记,暴力,并查集+分组背包

    A. Arpa’s hard exam and Mehrdad’s naive cheat time limit per test 1 second memory limit per test 256 ...

  4. POJ 1944 Fiber Communications (枚举 + 并查集 OR 线段树)

    题意 在一个有N(1 ≤ N ≤ 1,000)个点环形图上有P(1 ≤ P ≤ 10,000)对点需要连接.连接只能连接环上相邻的点.问至少需要连接几条边. 思路 突破点在于最后的结果一定不是一个环! ...

  5. BZOJ 1050: [HAOI2006]旅行comf(枚举+并查集)

    [HAOI2006]旅行comf Description 给你一个无向图,N(N<=500)个顶点, M(M<=5000)条边,每条边有一个权值Vi(Vi<30000).给你两个顶点 ...

  6. bzoj 4078: [Wf2014]Metal Processing Plant【二分+2-SAT+枚举+并查集】

    枚举从大到小s1,二分s2(越大越有可能符合),2-SAT判断,ans取min 思路倒是挺简单的,就是二分的时候出了比较诡异的问题,只能二分s2的值,不能在数组上二分... 有个优化,就是当不是二分图 ...

  7. bzoj 1050: [HAOI2006]旅行comf【枚举+并查集】

    m是5000,就想到了直接枚举比例 具体做法是是先把边按照边权从小到大排序,然后先枚举最小边权,再枚举最大边权,就是从最小边权里一个一个加进并查集里,每次查st是否联通,联通则退出,更新答案 #inc ...

  8. nyoj 711 枚举+并查集

     #include<stdio.h>//从大到小不断枚举边直到找到s-t的路径,判断从s可以到t可以用并查集来判断 #include<stdlib.h>//枚举最大的一条边肯定 ...

  9. P2502 [HAOI2006]旅行——暴力和并查集的完美结合

    P2502 [HAOI2006]旅行 一定要看清题目数据范围再决定用什么算法,我只看着是一个蓝题就想到了记录最短路径+最小生成树,但是我被绕进去了: 看到只有5000的边,我们完全可以枚举最小边和最大 ...

随机推荐

  1. 洛谷 P1121 环状最大两段子段和 题解

    每日一题 day57 打卡 Analysis 对于这个问题,由于分成了两个子序列,我们不妨就是枚举一下可能出现的情况: 无非就这两种: 1.+++++0000+++++0000++++ 2.0000+ ...

  2. MongoDB Index

    索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录. 这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要 ...

  3. luogu_4317: 花神的数论题

    花神的数论题 题意描述: 设\(sum(i)\)表示\(i\)的二进制数中\(1\)的个数. 给定一个整数\(N\),求\(\prod_{i=1}^Nsum(i)\). 输入描述: 输入包含一个正整数 ...

  4. 使用Maven创建一个普通java项目

    1.创建项目: 使用Maven目的是是我们能够轻松的管理各种别人写过的包 创建好之后,我们去找我们所需要的包:在mvnrepository.com中找自己所需要的包 例子: 最后将依赖写入pom.xm ...

  5. [linux][c/c++]代码片段02

    gcc `pkg-config --cflags gtk+-3.0` -o example-1 example-1.c `pkg-config --libs gtk+-3.0` #include &l ...

  6. Java8之list<entity>获取实体的某一字段

    示例 List<String> titles = titleList.stream().map(e -> e.get(ConstantUtil.TITLE)).collect(Col ...

  7. Ubuntu 17.10安装VirtualBox 5.2.2 及相关问题解决

    link:https://www.linuxidc.com/Linux/2017-11/148870.htm sudo apt update && sudo apt upgrade s ...

  8. PHP系列 | Thinkphp3.2 上传七牛 bad token 问题 [ layui.upload 图片/文件上传]

    前端代码 <div class="logo_out" id="upload-logo"></div> JS代码 /** * 上传图片 * ...

  9. C#-关于TcpListener的AcceptTcpClient()方法造成线程阻塞,进而程序无法彻底关闭的问题

    https://blog.csdn.net/nuistchn/article/details/50809158 在<C#高级编程>第7版第24章,有提到使用TCP类. 书中写了一个实例,两 ...

  10. Python3基础 is与== 区别

             Python : 3.7.3          OS : Ubuntu 18.04.2 LTS         IDE : pycharm-community-2019.1.3    ...