bzoj2429 [HAOI2006]聪明的猴子 最小生成树

Description


在一个热带雨林中生存着一群猴子,它们以树上的果子为生。昨天下了一场大雨,现在雨过天晴,但整个雨林的地
表还是被大水淹没着,部分植物的树冠露在水面上。猴子不会游泳,但跳跃能力比较强,它们仍然可以在露出水面
的不同树冠上来回穿梭,以找到喜欢吃的果实。现在,在这个地区露出水面的有N棵树,假设每棵树本身的直径都
很小,可以忽略不计。我们在这块区域上建立直角坐标系,则每一棵树的位置由其所对应的坐标表示(任意两棵树
的坐标都不相同)。在这个地区住着的猴子有M个,下雨时,它们都躲到了茂密高大的树冠中,没有被大水冲走。由
于各个猴子的年龄不同、身体素质不同,它们跳跃的能力不同。有的猴子跳跃的距离比较远(当然也可以跳到较近
的树上),而有些猴子跳跃的距离就比较近。这些猴子非常聪明,它们通过目测就可以准确地判断出自己能否跳到
对面的树上。【问题】 现已知猴子的数量及每一个猴子的最大跳跃距离,还知道露出水面的每一棵树的坐标,你
的任务是统计有多少个猴子可以在这个地区露出水面的所有树冠上觅食。

猴子的个数M(2<=M<=500);
树的总棵数N(2<=N<=1000);

Solution


题意比较麻烦。m个点最小生成树,如果一只猴子能跳过最长的边,那么这只猴子一定能跳完所有树

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
const int N=525005;
const int E=550005;
struct edge{int x,y,w;}e[E];
int fa[N],d[N],x[N],y[N],edCnt=0,ans=0,w;
int get_father(int now) {return (!fa[now])?(now):(fa[now]=get_father(fa[now]));}
int cmp(edge a,edge b) {return a.w<b.w;}
int merge(int x,int y) {x=get_father(x); y=get_father(y); return (x==y)?(0):((fa[x]=y)!=0);}
int main(void) {
    int n; scanf("%d",&n);
    rep(i,1,n) scanf("%d",&d[i]);
    int m; scanf("%d",&m);
    rep(i,1,m) scanf("%d%d",&x[i],&y[i]);
    rep(i,1,m) rep(j,i+1,m) e[++edCnt]=(edge){i,j,(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])};
    std:: sort(e+1,e+edCnt+1,cmp);
    rep(i,1,edCnt) if (merge(e[i].x,e[i].y)) w=e[i].w;
    rep(i,1,n) if (d[i]*d[i]>=w) ans++;
    printf("%d\n", ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值