[BZOJ 2429] 聪明的猴子

Link:

BZOJ 2429 传送门

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;
}

猜你喜欢

转载自www.cnblogs.com/newera/p/9127126.html