【C++】洛谷P2504 [HAOI2006]聪明的猴子

9 篇文章 0 订阅

[HAOI2006]聪明的猴子

题目描述

在一个热带雨林中生存着一群猴子,它们以树上的果子为生。昨天下了一场大雨,现在雨过天晴,但整个雨林的地表还是被大水淹没着,部分植物的树冠露在水面上。猴子不会游泳,但跳跃能力比较强,它们仍然可以在露出水面的不同树冠上来回穿梭,以找到喜欢吃的果实。

现在,在这个地区露出水面的有N棵树,假设每棵树本身的直径都很小,可以忽略不计。我们在这块区域上建立直角坐标系,则每一棵树的位置由其所对应的坐标表示(任意两棵树的坐标都不相同)。

在这个地区住着的猴子有M个,下雨时,它们都躲到了茂密高大的树冠中,没有被大水冲走。由于各个猴子的年龄不同、身体素质不同,它们跳跃的能力不同。有的猴子跳跃的距离比较远(当然也可以跳到较近的树上),而有些猴子跳跃的距离就比较近。这些猴子非常聪明,它们通过目测就可以准确地判断出自己能否跳到对面的树上。

【问题】现已知猴子的数量及每一个猴子的最大跳跃距离,还知道露出水面的每一棵树的坐标,你的任务是统计有多少个猴子可以在这个地区露出水面的所有树冠上觅食。

输入格式

输入文件monkey.in包括:

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

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

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

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

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

输出格式

输出文件monkey.out包括一个整数,表示可以在这个地区的所有树冠上觅食的猴子数。

样例 #1

样例输入 #1

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

样例输出 #1

3

提示

【数据规模】

对于40%的数据,保证有2<=N <=100,1<=M<=100

对于全部的数据,保证有2<=N <= 1000,1<=M=500

感谢@charlie003 修正数据

思路: 创建最小生成树,判断猴子的跳跃距离是否比生成树中的最长边大即可。

代码:

#include <bits/stdc++.h>
using namespace std;
struct trees{
    int x, y;
} t[1005];
struct point{
    int x, y;
    double dist;
} p[1000005];
int m, n, dis[1005], indexx, fa[1005], maxx, ans;
void init(){
    for(int i = 1; i <= n; i++) fa[i] = i;
}
int getfa(int x){
    return fa[x] == x ? x : (fa[x] = getfa(fa[x]));
}
void merge(int x, int y){
    fa[getfa(x)] = getfa(y);
}
bool check(int x, int y){
    return getfa(x) == getfa(y);
}
int main(){
    cin >> m;
    for(int i = 1; i <= m; i++){
        cin >> dis[i];
    }
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> t[i].x >> t[i].y;
    }
    for(int i = 1; i <= n; i++){
        for(int j = i + 1; j <= n; j++){
            p[indexx].x = i, p[indexx].y = j;
            p[indexx].dist = sqrt((t[i].x-t[j].x)*(t[i].x-t[j].x)+(t[i].y-t[j].y)*(t[i].y-t[j].y));
            indexx++;
        }
    }
    sort(p, p + indexx, [](point a, point b){
        return a.dist < b.dist;
    });
    int cnt = n;
    init();
    for(int i = 0; i < indexx; i++){
        if(cnt == 1){
            maxx = p[i - 1].dist;
            break;
        }
        if(!check(p[i].x, p[i].y)){
            merge(p[i].x, p[i].y);
            cnt--;
        }
    }
    for(int i = 1; i <= m; i++){
        if(dis[i] >= maxx) ans++;
    }
    cout << ans;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值