感觉回到了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; }