![](https://i-blog.csdnimg.cn/blog_migrate/da332b50682c17817c90c0144f4c45b8.png)
最小生成树的一个重要性质:最小生成树的最大边权是所有生成树的最大边权中最小的
所有只要做一个最小生成树,途中记录最大边权就可以了
我用的是kruskal来做生成树,最后把存猴子步长的数组遍历一遍看有多少能跳过最长的边就行了
#include <bits/stdc++.h>
using namespace std;
int p[1005],leap[505],x[1005],y[1005];
int M,N,num=0;
double MAX=-1; //用来存储最小生成树的最大边
struct Edge
{
int a,b;
double w;
}edge[5000000];
bool cmp(Edge A,Edge B) //一个按边长从小到大的排序方法
{
return A.w<B.w;
}
int find(int x) //并查集标准find函数
{
if(p[x] != x) return find(p[x]);
else return p[x];
}
int main()
{
scanf("%d",&M);
for(int i = 1; i <= M; i ++) scanf("%d",&leap[i]);
scanf("%d",&N);
for(int i = 1; i <= N; i ++) scanf("%d%d",&x[i],&y[i]);
//输入结束,该算边长了
int cnt = 0;
for(int i = 1; i <= N; i ++)
{
for(int j = 1; j <= N; j ++)
{
if(i != j)
{
edge[++cnt].a = i;
edge[cnt].b = j;
edge[cnt].w = sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
}
}
}
sort(edge + 1,edge + cnt + 1,cmp); //按照边长排序
for(int i = 1; i <= N; i ++) p[i] = i; //并查集初始化
int k = N; 一共连接N-1次 所以在k=1时退出
for(int i = 1; i <= cnt; i ++)
{
if(k == 1) break; //图已连成
int a,b;
double w;
a = edge[i].a, b = edge[i].b, w = edge[i].w;
if(find(a) == find(b)) continue; //已经联通就不处理了
p[find(a)] = b;
k--;
if(w > MAX) MAX = w; //其实没必要if因为边长是递增的
}
for(int i = 1; i <= M; i ++)
if(leap[i] >= MAX) num++;
printf("%d",num);
return 0;
}