【洛谷P2504】聰明的猴子 最小瓶頸樹
阿新 • • 發佈:2018-12-04
題目大意:給定一張 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; }