BZOJ 2429: [HAOI2006]聪明的猴子【最小生成树】
2429: [HAOI2006]聪明的猴子
Time Limit: 10 Sec Memory Limit: 128 MB
Description
在一个热带雨林中生存着一群猴子,它们以树上的果子为生。昨天下了一场大雨,现在雨过天晴,但整个雨林的地表还是被大水淹没着,部分植物的树冠露在水面上。猴子不会游泳,但跳跃能力比较强,它们仍然可以在露出水面的不同树冠上来回穿梭,以找到喜欢吃的果实。现在,在这个地区露出水面的有N棵树,假设每棵树本身的直径都很小,可以忽略不计。我们在这块区域上建立直角坐标系,则每一棵树的位置由其所对应的坐标表示(任意两棵树的坐标都不相同)。在这个地区住着的猴子有M个,下雨时,它们都躲到了茂密高大的树冠中,没有被大水冲走。由于各个猴子的年龄不同、身体素质不同,它们跳跃的能力不同。有的猴子跳跃的距离比较远(当然也可以跳到较近的树上),而有些猴子跳跃的距离就比较近。这些猴子非常聪明,它们通过目测就可以准确地判断出自己能否跳到对面的树上。
【问题】 现已知猴子的数量及每一个猴子的最大跳跃距离,还知道露出水面的每一棵树的坐标,你的任务是统计有多少个猴子可以在这个地区露出水面的所有树冠上觅食。
Input
第1行为一个整数,表示猴子的个数M(2<=M<=500);
第2行为M个整数,依次表示猴子的最大跳跃距离(每个整数值在1–1000之间);
第3行为一个整数表示树的总棵数N(2<=N<=1000);
第4行至第N+3行为N棵树的坐标(横纵坐标均为整数,范围为:-1000–1000)。
(同一行的整数间用空格分开)
Output
包括一个整数,表示可以在这个地区的所有树冠上觅食的猴子数
Sample Input
4
1 2 3 4
6
0 0
1 0
1 2
-1 -1
-2 0
2 2
Sample Output
3
HINT
2<=N <= 1000,1<=M=500
题解
裸的最小生成树,猴子肯定跳最短的距离,那么最小生成树最大边,然后check一趟就可以了。
代码如下
#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;
const int maxn=1005,maxm=505,maxe=500005;
int n,m,ans,S,E,fa[maxn],s[maxm],x[maxn],y[maxn];
struct xcw{
int x,y,w;
bool operator <(const xcw x)const{return w<x.w;}
}a[maxe];
inline int read(){
int ret=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-')f=-f;ch=getchar();}
while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
int get_dist(int i,int j){return (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);}
int get_fa(int x){return fa[x]==x?x:fa[x]=get_fa(fa[x]);}
void kruscal(){
for (int i=1;i<n;i++)
for (int j=i+1;j<=n;j++)
a[++E].x=i,a[E].y=j,a[E].w=get_dist(i,j);
sort(a+1,a+1+E);
int cnt=0;
for (int i=1;i<=E;i++){
if (cnt==n-1) break;
int fx=get_fa(a[i].x),fy=get_fa(a[i].y);
if (fx==fy) continue;
cnt++,fa[fx]=fy,S=max(S,a[i].w);
}
}
int main(){
m=read();
for (int i=1;i<=m;i++) s[i]=read();
n=read();
for (int i=1;i<=n;i++) x[i]=read(),y[i]=read(),fa[i]=i;;
kruscal();
for (int i=1;i<=m;i++)
if (s[i]*s[i]>=S) ans++;
printf("%d\n",ans);
return 0;
}