1. 程式人生 > >【洛谷P2504】聰明的猴子 最小瓶頸樹

【洛谷P2504】聰明的猴子 最小瓶頸樹

題目大意:給定一張 N 個頂點的完全圖,邊有邊權,求該完全圖的一棵最小瓶頸樹。

最小瓶頸樹:一棵最大邊權值在同一張圖的所有生成樹中最小,即:最大邊權值最小的生成樹,其值為該樹的最大邊權的權值。
引理1:最小生成樹一定是一棵最小瓶頸樹。
證明:若最小生成樹不是最小瓶頸樹,則意味著存在一條邊的權值大於最小瓶頸樹的最大邊權值,那麼將 MST 的該邊去掉,則將一棵樹變成了不連通的兩棵樹,再將最小瓶頸樹的一條連線這兩個聯通塊的邊加入 MST,可以得到一棵權值更小的生成樹,與 MST 性質矛盾,證畢。

引理2:最小瓶頸樹不一定是最小生成樹。
證明:證明

程式碼如下

#include <bits/stdc++.h>
using namespace std;
const int maxe=1e6+10;
const int maxv=1010;

inline int read(){
    int x=0,f=1;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
    do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
    return f*x;
}

int n,m,tot,d[maxv>>1],f[maxv],sum,path,cnt;
struct node{int x,y;}p[maxv];
struct edge{int from,to,w;}e[maxe];

bool cmp(const edge& x,const edge& y){return x.w<y.w;}

inline int get_dis(int a,int b){
    return (p[a].x-p[b].x)*(p[a].x-p[b].x)+(p[a].y-p[b].y)*(p[a].y-p[b].y);
}

void read_and_parse(){
    m=read();
    for(int i=1;i<=m;i++)d[i]=read();
    sum=n=read();
    for(int i=1;i<=n;i++)p[i].x=read(),p[i].y=read();
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            e[++tot]=edge{i,j,get_dis(i,j)};
}

int find(int x){return x==f[x]?f[x]:f[x]=find(f[x]);}

int kruskal(){
    int src;
    for(int i=1;i<=n;i++)f[i]=i;
    sort(e+1,e+tot+1,cmp);
    for(int i=1;i<=tot&&sum>1;i++){
        int x=find(e[i].from),y=find(e[i].to);
        if(x==y)continue;
        f[x]=y,--sum,src=e[i].w;
    }
    return src;
}

void solve(){
    path=kruskal();
    for(int i=1;i<=m;i++)if(d[i]*d[i]>=path)++cnt;
    printf("%d\n",cnt);
}

int main(){
    read_and_parse();
    solve();
    return 0;
}