[HAOI2006]聪明的猴子

链接:https://ac.nowcoder.com/acm/problem/19964
来源:牛客网
 

题目描述

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

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

输入描述:

第1行为一个整数,表示猴子的个数M(2 ≤ M ≤ 500);
第2行为M个整数,依次表示猴子的最大跳跃距离(每个整数值在1--1000之间);
第3行为一个整数表示树的总棵数N(2 ≤ N ≤ 1000);
第4行至第N+3行为N棵树的坐标(横纵坐标均为整数,范围为:-1000--1000)。(同一行的整数间用空格分开)

输出描述:

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

示例1

输入

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

输出

本题用克鲁斯卡尔算法,注意:边数要远远大于树的个数
#include <stdio.h>
#include <math.h> 
#include <algorithm>
using namespace std;
const int maxv=10001; 
struct edge{
	int u,v;
	double dis;
}E[100000000];
int father[100000000];
int n,m,x[maxv],y[maxv];
double M[maxv];//猴子,坐标 
int findfather(int X){
	int a=X;
	while(X!=father[X]){
		X=father[X];
	}
	while(a!=father[a]){
		int z=a;
		a=father[a];
		father[z]=X;
	}
	return X;
}
bool cmp(edge a,edge b){
	return a.dis<b.dis;
}
int kruscal(int n){
	int ans=1;//记录边的个数 
	for(int i=1;i<=n;i++){//记录边和距离 
		for(int j=i+1;j<=n;j++){
			if(j<=n){
				E[ans].u=i;
				E[ans].v=j;
				E[ans++].dis=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
				//printf("%d %d\n",i,j);
			}
		}
	}
	ans-=1;
//	printf("%d\n",ans);
	for(int i=1;i<=ans;i++){//初始化 
		father[i]=i;
	}
	sort(E+1,E+ans+1,cmp); //边从小到大排序 
	double mdis=0.0;int e_num=0;
	for(int i=1;i<=ans;i++){//循环边数 
		int faU=findfather(E[i].u);
		int faV=findfather(E[i].v);
		if(faU!=faV){
		father[faV]=faU;
			e_num++;
			if(e_num==n-1){
				mdis=E[i].dis;//最大的边 
				break;
			}
		}
	}
	if(e_num!=n-1){
		return -1;
	}else{
		return mdis;
	} 
}
int main(){
	scanf("%d",&m);
	for(int i=0;i<m;i++){
		scanf("%lf",&M[i]);
	}
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d",&x[i],&y[i]);
	}
	double ans=kruscal(n);
	if(ans==-1.0){
		printf("0\n");
	}else{
		int sum=0;
		for(int i=0;i<m;i++){
			if(ans<=M[i]){
				sum++;
			}
		}
		printf("%d\n",sum);
	}
	return 0;
} 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值