LOI2504 [HAOI2006]聪明的猴子

题目描述

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

分析

最小生成树模型

#include <bits/stdc++.h>
#define rep( i , l , r ) for( int i = (l) ; i <= (r) ; ++i )
#define per( i , r , l ) for( int i = (r) ; i >= (l) ; --i )
#define erep( i , u ) for( int i = head[(u)] ; ~i ; i = e[i].nxt )
using namespace std;
int _read(){
    char ch = getchar();
    int x = 0 , f = 1 ;
    while( !isdigit( ch ) )
           if( ch == '-' ) f = -1 , ch = getchar();
           else ch = getchar();
    while( isdigit( ch ) )
           x = (ch  - '0') + x * 10 , ch =  getchar();
    return x * f;
}
const int maxn = 1000 + 5 , maxm = 2500000 + 5;
struct edge{
    int u , v , w;
} e[maxm];
#define PII pair<int,int>
#define FR first
#define SE second
PII a[maxn];
int f[maxn] , _t = 0;
int get_f( int x ){
    if( f[x] == x ) return x;
    else return f[x] = get_f( f[x] );
}
inline bool cmp( const edge &a , const edge &b ){
    return a.w < b.w;
}
const int INF = 0x7f7f7f7f;
int dis[maxn];
int main(){
    int M = _read();
    rep( i , 1 , M ) dis[i] = _read();
    int N = _read();
    rep( i , 1 , N ){
        a[i].FR = _read() , a[i].SE = _read();
        rep( j , 1 , i - 1 ){
            int w = (a[i].FR - a[j].FR) * (a[i].FR - a[j].FR) 
                 +  (a[i].SE - a[j].SE) * (a[i].SE - a[j].SE);
            _t++; e[_t].u = i , e[_t].v = j , e[_t].w = w;
        }
    }
    sort( e + 1 , e + _t + 1 , cmp );
    rep( i , 1 , N ) f[i] = i;
    int ans = 0;
    rep( i , 1 , _t ){
        int fx = get_f( e[i].u ) , fy = get_f( e[i].v );
        if( fx == fy ) continue;
        f[fx] = fy;
        ans = e[i].w;
    }
    int res = 0;
    rep( i , 1 , M )
        if( dis[i] * dis[i] >= ans ) ++res;
    cout << res << endl;    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值