A — Fence Planning
题目大意:
农民约翰的N头奶牛,方便地编号为1…N(2≤N≤105),有一个复杂的社会结构,围绕着“moo网络”——小群的奶牛,它们在自己的群体中交流,但不与其他群体交流。每头奶牛位于2D的农场地图上不同的(x,y)位置,我们知道有M对奶牛(1≤M<105)在互相moo叫。互相moo叫的两头牛属于同一个moo网络。为了更新他的农场,农民约翰想要建一个长方形的栅栏,栅栏的边缘平行于x轴和y轴。农民John想要确保至少有一个moo网络是完全被栅栏围起来的(矩形边界上的牛算作被围起来的)。请帮助农民约翰确定满足这一要求的篱笆的最小周长。这个栅栏可能是零宽或零高。
输入
第一行包含N和M,
接下来的N行分别包含一头奶牛的x和y坐标(大小不超过108的非负整数)。
接下来的M行分别包含两个整数a和b,它们描述了奶牛a和奶牛b之间的moo连接。每头奶牛至少有一个moo连接,输入中没有重复的连接。
输出
请打印满足农民约翰要求的篱笆最小周长。
题目分析:
运用并查集存图,让每个群体的代表,即父亲拥有整个群体的范围,通过遍历每个父亲可以更新最小周长。
代码实现:
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long LL;
const int maxn = 100007;
struct cow
{
int x;
int y;
}c[maxn];
struct node
{
int u;
int v;
}es[maxn];
int fa[maxn];
int zzzzz[maxn][4] = {0}; //每头牛所连的群体的范围,分别为最左,最右,最上,最下
void init(int n) //初始化
{
for(int i=1; i<=n; i++){
fa[i] = i;
zzzzz[i][0] = zzzzz[i][1] = c[i].x;
zzzzz[i][2] = zzzzz[i][3] = c[i].y;
}
}
int find_f(int x) //找父亲
{
int r = x;
while(fa[r]!=r) r = fa[r];
return r;
}
void uni(int x, int y) //连接,同时更新这个群体的范围
{
fa[x] = y;
if(zzzzz[x][0]<zzzzz[y][0]) zzzzz[y][0] = zzzzz[x][0];
if(zzzzz[x][1]>zzzzz[y][1]) zzzzz[y][1] = zzzzz[x][1];
if(zzzzz[x][2]>zzzzz[y][2]) zzzzz[y][2] = zzzzz[x][2];
if(zzzzz[x][3]<zzzzz[y][3]) zzzzz[y][3] = zzzzz[x][3];
}
int main()
{
int n,m;
cin >> n >> m;
for(int i=1; i<=n; i++){
scanf("%d%d",&c[i].x,&c[i].y);
}
for(int i=0; i<m; i++){
scanf("%d%d",&es[i].u,&es[i].v);
}
init(n);
for(int i=0; i<m; i++){
int fu = find_f(es[i].u);
int fv = find_f(es[i].v);
if(fu!=fv) uni(fu,fv);
}
LL ans = 99999999999;
for(int i=1; i<=n; i++){
if(fa[i]==i){
LL C = ((zzzzz[i][1]-zzzzz[i][0])+(zzzzz[i][2]-zzzzz[i][3]))*2; //求周长
ans = min(ans,C);
}
}
printf("%lld\n",ans);
return 0;
}