【NOIP模拟赛】矩形
【NOIP模拟赛】矩形
题目描述
在一个平面坐标系上有n个点,编号为1到n,它们之间m条无向边。有边相连的点表示它们属于同一类。现在要用一个边框平行于坐标轴的矩形将一个类别的点全部覆盖,求矩形的最小周长 。每一个顶点的度至少为1.
输入
输入的第一行包含N和M。以下N行每行包含一个点的x坐标和y坐标(至多108的非负整数)。以下M行每行包含两个整数a和b。
输出
矩形的最小周长。
样例输入 Copy
7 5 0 5 10 5 5 0 5 10 6 7 8 6 8 4 1 2 2 3 3 4 5 6 7 6
样例输出 Copy
10
首篇博客,拿道新题祭天了。顺提今天的模拟赛,三道题让我对NOIP路愈加迷茫。就两个人最高,总分100,A了这题,另外两道更是分都没骗到==(50分的Enderman瑟瑟发抖)。
初始分析忽略了同一类这个问题,直接去找了横纵坐标的最值,没过样例。回头看题,这才想起a,b是有实用的。梳理清思路,发现这就是个无向图。
不停更新最值同时还得找最小范围,也就是图的生成树中生成范围最小的那个。这里笔者考虑到了并查集,将同一个连通块的点合并,记录这个连通块的最值,确定下矩形再比较周长(老师给出的题解)。
下来问penguin等人也用的并查集。然而我们都WA了。我只过了三个点,penguin过了两个。肝帝用并查集超时80%。我们没有死磕并查集,还是选择了另一种做法:就用邻接表遍历一遍,更新答案!
用这个方法得注意跳出循环。这样做虽然会慢一点,但对于本题时间还是绰绰有余的。
附上领接表代码
#include<bits/stdc++.h> #define smax 100005 using namespace std; int n,m,cnt,xmin,xmax,ymin,ymax,c,cmin=1000000000; bool vis[smax]; struct edge { int x,y; }ed[smax]; vector<int>p[smax]; void find(int k) { vis[k]=1; xmin=min(xmin,ed[k].x);//更新最值ing xmax=max(xmax,ed[k].x); ymin=min(ymin,ed[k].y); ymax=max(ymax,ed[k].y); for(int i=0;i<p[k].size();i++)//判断是否访问。如果不判断,将无法退出循环! if(!vis[p[k][i]]) find(p[k][i]); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { int x1,y1; scanf("%d%d",&x1,&y1); ed[++cnt].x=x1; ed[cnt].y=y1; } for(int i=1;i<=m;i++) { int a,b; scanf("%d%d",&a,&b); p[a].push_back(b); p[b].push_back(a);//无向图 } for(int i=1;i<=n;i++) { if(!vis[i]) { xmin=100000001; xmax=-1; ymin=100000001; ymax=-1; find(i); c=2*(xmax-xmin)+2*(ymax-ymin); if(c<cmin) //更新答案 cmin=c; } } printf("%d",cmin); return 0; }
更新一波。
经过不断地探讨以及对真理的不懈追求(肝帝的高技术力),鄙人终于将源代码改出来了,也就是用并查集完善这道题。并查集的确优化了程序使程序更快了。
附上AC代码
//rectangle #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define maxn 100005 using namespace std; int fa[maxn],minx[maxn],maxx[maxn],miny[maxn],maxy[maxn]; int n,m,t1,t2,minc[maxn],ans=10000000000; int find(int x) { if(fa[x]==0) return x; return fa[x]=find(fa[x]); } void merge(int a,int b) { a=find(a); b=find(b); fa[a]=b; if(minx[a]<minx[b]) minx[b]=minx[a]; if(maxx[a]>maxx[b]) maxx[b]=maxx[a]; if(miny[a]<miny[b]) miny[b]=miny[a]; if(maxy[a]>maxy[b]) maxy[b]=maxy[a]; minc[b]=2*((maxx[b]-minx[b])+(maxy[b]-miny[b])); } int main() { //freopen("rectangle.in","r",stdin); //freopen("rectangle.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d%d",&t1,&t2); minx[i]=t1; maxx[i]=t1; miny[i]=t2; maxy[i]=t2; } for(int i=1;i<=m;i++) { scanf("%d%d",&t1,&t2); if(find(t1)!=find(t2)) merge(t1,t2); } for(int i=1;i<=n;i++) if(minc[i]<ans&&fa[i]==0) ans=minc[i]; printf("%d",ans); return 0; }
据肝帝说,merge里的if语句换成max和min会更快哦!
新人博主,还望多多关照,多多提意见!

浙公网安备 33010602011771号