聪明的猴子(BZOJ 2429)
题目描述
在一个热带雨林中生存着一群猴子,它们以树上的果子为生。昨天下了一场大雨,现在雨过天晴,但整个雨林的地表还是被大水淹没着,部分植物的树冠露在水面上。猴子不会游泳,但跳跃能力比较强,它们仍然可以在露出水面的不同树冠上来回穿梭,以找到喜欢吃的果实。
现在,在这个地区露出水面的有N棵树,假设每棵树本身的直径都很小,可以忽略不计。我们在这块区域上建立直角坐标系,则每一棵树的位置由其所对应的坐标表示(任意两棵树的坐标都不相同)。
在这个地区住着的猴子有M个,下雨时,它们都躲到了茂密高大的树冠中,没有被大水冲走。由于各个猴子的年龄不同、身体素质不同,它们跳跃的能力不同。有的猴子跳跃的距离比较远(当然也可以跳到较近的树上),而有些猴子跳跃的距离就比较近。这些猴子非常聪明,它们通过目测就可以准确地判断出自己能否跳到对面的树上。
【问题】 现已知猴子的数量及每一个猴子的最大跳跃距离,还知道露出水面的每一棵树的坐标,你的任务是统计有多少个猴子可以在这个地区露出水面的所有树冠上觅食。
输入
第1行为一个整数,表示猴子的个数M(2<=M<=500);
第2行为M个整数,依次表示猴子的最大跳跃距离(每个整数值在1--1000之间);
第3行为一个整数表示树的总棵数N(2<=N<=1000);
第4行至第N+3行为N棵树的坐标(横纵坐标均为整数,范围为:-1000--1000)。
(同一行的整数间用空格分开)
输出
包括一个整数,表示可以在这个地区的所有树冠上觅食的猴子数
样例输入
4
1 2 3 4
6
0 0
1 0
1 2
-1 -1
-2 0
2 2
1 2 3 4
6
0 0
1 0
1 2
-1 -1
-2 0
2 2
样例输出
3
提示
对于40%的数据,保证有2<=N <=100,1<=M<=100
对于全部的数据,保证有2<=N <= 1000,1<=M=500
/* 要想让一只猴子跳完全部的点,很显然这些点必须是联通的,所以要 形成一棵树,而且这棵树每条边的路径越短,通过的猴子数目越多, 所以要形成一棵最小生成树,一个猴子能跳过这棵树上的最长边,就能 通过这棵树。 */ #include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #define M 1010 #define N 510 using namespace std; int fa[M],n,m,cnt; double can[N],x[M],y[M],a[M][M],ans; struct node { int a,b; double dis; };node e[M*M]; int read() { char c=getchar();int flag=1,num=0; while(c<'0'||c>'9'){if(c=='-')flag=-1;c=getchar();} while(c>='0'&&c<='9'){num=num*10+c-'0';c=getchar();} return num*flag; } int cmp(const node&x,const node&y) { return x.dis<y.dis; } int find(int x) { if(fa[x]==x)return x; return fa[x]=find(fa[x]); } int main() { n=read(); for(int i=1;i<=n;i++) can[i]=read(); m=read(); for(int i=1;i<=m;i++) { fa[i]=i; x[i]=read(); y[i]=read(); } for(int i=1;i<=m;i++) for(int j=i+1;j<=m;j++) { ++cnt; e[cnt].a=i; e[cnt].b=j; e[cnt].dis=sqrt(pow(double(x[i]-x[j]),2)+pow(double(y[i]-y[j]),2)); } sort(e+1,e+cnt+1,cmp); for(int i=1;i<=cnt;i++) { int a=find(e[i].a); int b=find(e[i].b); if(a!=b) { fa[a]=b; ans=max(ans,e[i].dis); } } int tot=0; for(int i=1;i<=n;i++) if(can[i]>=ans)tot++; printf("%d",tot); return 0; }