BZOJ 2429 [HAOI2006]聪明的猴子 MST最小生成树

Description

在一个热带雨林中生存着一群猴子,它们以树上的果子为生。昨天下了一场大雨,现在雨过天晴,但整个雨林的地

表还是被大水淹没着,部分植物的树冠露在水面上。猴子不会游泳,但跳跃能力比较强,它们仍然可以在露出水面

的不同树冠上来回穿梭,以找到喜欢吃的果实。现在,在这个地区露出水面的有N棵树,假设每棵树本身的直径都

很小,可以忽略不计。我们在这块区域上建立直角坐标系,则每一棵树的位置由其所对应的坐标表示(任意两棵树

的坐标都不相同)。在这个地区住着的猴子有M个,下雨时,它们都躲到了茂密高大的树冠中,没有被大水冲走。由

于各个猴子的年龄不同、身体素质不同,它们跳跃的能力不同。有的猴子跳跃的距离比较远(当然也可以跳到较近

的树上),而有些猴子跳跃的距离就比较近。这些猴子非常聪明,它们通过目测就可以准确地判断出自己能否跳到

对面的树上。【问题】 现已知猴子的数量及每一个猴子的最大跳跃距离,还知道露出水面的每一棵树的坐标,你

的任务是统计有多少个猴子可以在这个地区露出水面的所有树冠上觅食。


Input

第1行为一个整数,表示猴子的个数M(2<=M<=500);

第2行为M个整数,依次表示猴子的最大跳跃距离(每个整数值在1–1000之间);

第3行为一个整数表示树的总棵数N(2<=N<=1000);

第4行至第N+3行为N棵树的坐标(横纵坐标均为整数,范围为:-1000–1000)。

(同一行的整数间用空格分开)


Output

包括一个整数,表示可以在这个地区的所有树冠上觅食的猴子数


Sample Input

4
1 2 3 4
6
0 0
1 0
1 2
-1 -1
-2 0
2 2


Sample Output

3


Hint

2<=N <= 1000,1<=M=500


显然我们只需要把N*(N-1)条边进行最小生成树操作,只要猴子的距离大于最小生成树的最长边,就可以跳过,反之不可跳过


#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN=1000*1000+10;
int cnt,ccnt;
struct Line{
    int from,to;
    double len;
}line[MAXN];
int N,x[MAXN],y[MAXN],tail;
bool cmp(const Line &A,const Line &B){ return A.len<B.len; }
int M,dis[MAXN];
bool vis[MAXN+10];
int fa[MAXN];
void build(){
    for(register int i=1;i<=N;i++){
        for(register int j=1;j<=N;j++){
            if(i!=j){
                double temp=(double)sqrt((double)(x[i]-x[j])*(x[i]-x[j])+(double)(y[i]-y[j])*(y[i]-y[j]));
                tail++;
                line[tail].from=i;
                line[tail].to=j;
                line[tail].len=temp; 
            }
        }
    }
}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
double MST(){
    for(register int i=1;i<=N;i++) fa[i]=i;
    double maxn=-1.0;
    //for(register int i=1;i<=tail;i++) printf("%lf ",line[i].len);
    sort(line+1,line+tail+1,cmp);
    //printf("\n\n\n\n");
    //for(register int i=1;i<=tail;i++) printf("%lf ",line[i].len);
    //printf("%lf",line[tail].len);
    for(register int i=1;i<=tail;i++){
        int f=line[i].from,t=line[i].to;
        int fax=find(f),fay=find(t);
        if(fax==fay) continue;
        else{
            fa[fay]=fax;
            maxn=max(maxn,line[i].len);
        }
    }
    return maxn;
}
int main(){
    freopen("ACM_C.txt","r",stdin);
    scanf("%d",&M);
    for(register int i=1;i<=M;i++) scanf("%d",&dis[i]);
    scanf("%d",&N);
    for(register int i=1;i<=N;i++) scanf("%d%d",&x[i],&y[i]);
    build();
    double maxn=MST();
    for(register int i=1;i<=M;i++){
        if(dis[i]*1.0>=maxn) cnt++; 
    }
    printf("%d\n",cnt);
}

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值