题目描述
在一个热带雨林中生存着一群猴子,它们以树上的果子为生。昨天下了一场大雨,现在雨过天晴,但整个雨林的地表还是被大水淹没着,部分植物的树冠露在水面上。猴子不会游泳,但跳跃能力比较强,它们仍然可以在露出水面的不同树冠上来回穿梭,以找到喜欢吃的果实。
现在,在这个地区露出水面的有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复制
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
提示:这道题可以理解为最小生成树的做法来连通全图,然后用全图中两点最长的距离和每个猴子跳跃距离去比较,最终得出答案。
代码实现
#include<cmath>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int hz[100005];
int ax[100005],ay[100005];
struct edge{
int u,v,w,next;
bool operator <(const edge &a)const{
return w<a.w;
}
}e[1000005];
int f[100005];
int vis[100005];
int js(int x,int y){
return 1ll*(ax[x]-ax[y])*(ax[x]-ax[y])+1ll*(ay[x]-ay[y])*(ay[x]-ay[y]);
}
int getf(int x){
return x==f[x]?x:f[x]=getf(f[x]);
}
int ecnt=0;
void add(int u,int v ,int w){
e[++ecnt].u=u;
e[ecnt].v=v;
e[ecnt].w=w;
}
int n,m;
int main(){
cin>>m;
for(int i=1;i<=m;i++){
cin>>hz[i];
}
cin>>n;
for(int i=1;i<=n;i++){
cin>>ax[i]>>ay[i];
}
for(int i=1;i<=n;i++){
f[i]=i;
}
for(int i=1;i<n;i++){
for(int j=i+1;j<=n;j++){
add(i,j,js(i,j));
}
}
int cnt=0;
double ans=-1;
sort(e+1,e+1+ecnt);
for(int i=1;i<=ecnt;i++){
int u=getf(e[i].u);
int v=getf(e[i].v);
if(u!=v){
cnt++;
ans=max(ans,sqrt(e[i].w));//在这里稍加改动,记录一下最长距离
f[u]=v;
if(cnt==n-1){
break;
}
}
}
int as=0;
for(int i=1;i<=m;i++){
if(ans<=hz[i]){
as++;
}
}
cout<<as;
}
克鲁斯卡尔算法如有不懂可以看这里克鲁斯卡尔算法详解
都看到这了,关注一下吧^^