【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;
}
View Code

更新一波。

经过不断地探讨以及对真理的不懈追求(肝帝的高技术力),鄙人终于将源代码改出来了,也就是用并查集完善这道题。并查集的确优化了程序使程序更快了。

附上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;
}
View Code

 


 据肝帝说,merge里的if语句换成max和min会更快哦!

 

新人博主,还望多多关照,多多提意见!

posted @ 2019-08-14 22:51  -Enderman-  阅读(214)  评论(0)    收藏  举报