洛谷 P2504 [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包括一个整数,表示可以在这个地区的所有树冠上觅食的猴子数。
输入输出样例
说明
【数据规模】
对于40%的数据,保证有2<=N <=100,1<=M<=100
对于全部的数据,保证有2<=N <= 1000,1<=M=500
思路:求出每两棵树的间距,根据间距求最小生成树,最小生成树中权值最大的边即为猴子需要跳的最大距离,然后枚举猴子能跳的最远距离,与这个权值相比较即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <algorithm> #include <cstring> #include <cstdio> #include <cmath> using namespace std; const int M = 1000000; double sum; int n, m, k; int tot, ans; int x[M], y[M]; int fa[M], far[M]; struct nond { int u, v; double w; }e[M]; int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); } bool cmp(nond x, nond y) { return x.w < y.w; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &far[i]); scanf("%d", &m); for (int i = 1; i <= m; i++) { fa[i] = i; scanf("%d%d", &x[i], &y[i]); } for (int i = 1; i <= m; i++) for (int j = i + 1; j <= m; j++) { double tmp = sqrt((double)(x[i]-x[j])*(x[i]-x[j]) + (double)(y[i]-y[j])*(y[i]-y[j])); e[++k].u = i; e[k].v = j; e[k].w = tmp; } sort(e + 1, e + k + 1, cmp); for (int i = 1; i <= k; i++) { int x = find(e[i].u), y = find(e[i].v); if (x == y) continue; fa[x] = y; tot++; sum = max(e[i].w, sum); if (tot == m - 1) break; } for (int i = 1; i <= n; i++) if (far[i] >= sum) ans++; printf("%d\n", ans); return 0; }