感觉回到了NOIP水平。
最小生成树有一个性质就是最小生成树必为最小瓶颈生成树,即最大边的边权最小(从kruskal算法的构造过程很容易看出这点,毕竟是从小到大加边),于是此题很水,MST求完后最后加的那条边就是树上的最大边,用每个猴子的半径比一下就好了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=1000+5;
struct Edge{
int u,v;
double w;
bool operator<(const Edge &rhs)const{
return w<rhs.w;
}
}e[N*N];
inline int read(){
int x=0,f=1;char ch;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int x[N],y[N];
inline double sqr(double x){return x*x;}
inline double dist(int i,int j){
return sqrt(sqr(x[i]-x[j])+sqr(y[i]-y[j]));
}
int pa[N],r[N],m,n,cnt;
int findset(int x){
return pa[x]!=x?pa[x]=findset(pa[x]):x;
}
double MST(){
for(int i=1;i<=n;i++)pa[i]=i;
sort(e+1,e+1+cnt);
int tot=0;
for(int i=1;i<=cnt;i++){
int u=findset(e[i].u),v=findset(e[i].v);
if(u!=v){
pa[u]=v;
tot++;
if(tot==n-1)return e[i].w;
}
}
}
int main(){
m=read();
for(int i=1;i<=m;i++)r[i]=read();
n=read();
for(int i=1;i<=n;i++)x[i]=read(),y[i]=read();
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++){
cnt++;
e[cnt].u=i;e[cnt].v=j;e[cnt].w=dist(i,j);
}
double limit=MST();
int ans=0;
for(int i=1;i<=m;i++)
if(r[i]>=limit)ans++;
printf("%d",ans);
return 0;
}