[BZOJ 2429] 聪明的猴子
Link:
Solution:
可将题意转化为求使原图连通的子图中最长边的最小值,
那么立即联想到求最小生成树的Kruscal算法:每次选择最短的边加入答案集合
最小生成树的最长边就是要求的值
正确性是显然的(边权是从小到大选取的),而这也是最小生成树的推论之一:
对于任意一个连通图,图中A点走到B点的所有路径中,最长的边最小值是肯定出现在最小生成树中A到B的路径上
最后计算结果即可
Code:
#include <bits/stdc++.h> using namespace std; typedef pair<int,int> P; #define X first #define Y second const int MAXN=1e3+10; P dat[MAXN]; int n,m,jump[MAXN],f[MAXN],cnt=0,tot=0,mx=0,res=0; struct edge{int x,y,v;}e[MAXN*MAXN]; bool cmp(edge a,edge b){return a.v<b.v;} int ufs_find(int x){return (f[x]==x)?x:f[x]=ufs_find(f[x]);} int main() { scanf("%d",&m); for(int i=1;i<=m;i++) scanf("%d",&jump[i]); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&dat[i].X,&dat[i].Y),f[i]=i; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) //只记录平方值防止精度问题 e[++cnt]=edge{i,j,(dat[i].X-dat[j].X)*(dat[i].X-dat[j].X)+(dat[i].Y-dat[j].Y)*(dat[i].Y-dat[j].Y)}; sort(e+1,e+cnt+1,cmp); for(int i=1;i<=cnt;i++) { int posx=ufs_find(e[i].x),posy=ufs_find(e[i].y); if(posx!=posy) { f[posx]=posy;tot++; if(tot==n-1){mx=e[i].v;break;} } } for(int i=1;i<=m;i++) if(jump[i]*jump[i]>=mx) res++; printf("%d",res); return 0; }