所谓最小瓶颈生成树....就是使得生成树树上最大边权值最小。
这里主要介绍一种期望O(M)(线性)的求法,其实主要就是二分,具体思路如下:
类比找第k大值的方法,首先随机一个边权w。
然后将不超过这个边权的边加入,遍历这张图。
如果图连通,那么瓶颈不超过w,于是只需考虑边权不超过w的边。
否则将这些连通点缩起来,考虑边权大于w的边。
每次将问题的规模缩小至一半。
期望时间复杂度O(m)。
相关例题有两道:
A.Hangar Hurdles (CERC 16)
有一个n*n的网格图,上面有些格子可行,有些格子是障碍。 有Q个询问,想把一个正方形箱子从(r1,c1)推到(r2,c2),问箱子最大的大小。(起点终点是正方形箱子的中点) N<=1000 Q<=300000
B.洪蛤吨有一个宽度为L的管道,我们可以视其为一条y=L的直线与X轴所夹的部分。
(所以这根管道的长度可以视为正无穷)
这个管道中有个N个障碍点,第i个障碍点的坐标为(Xi,Yi)。
已知有一个球体,能在不碰到障碍点的前提下,从管道的最左端走到最右端。(即从管道内横坐标负无穷的地方走到横坐标正无穷的地方)。
求这个球体的直径最大是多少。为了避免精度误差,请输出答案保留三位小数的结果。
两题有异曲同工之妙a...(/滑稽,思路差不多...)都可以用最小瓶颈树实现复杂度最小
下面上一下t2的代码:(没有用最小瓶颈树优化,逃)
1 #include<bits/stdc++.h> 2 #define maxn 505 3 using namespace std; 4 struct eage{ 5 int u,v; 6 double dist; 7 }e[maxn*maxn/2+maxn*2]; 8 bool cmp(eage a,eage b){ 9 return a.dist<b.dist; 10 } 11 double dis(int x1,int y1,int x2,int y2){ 12 return sqrt(1.0*(x1-x2)*(x1-x2)+1.0*(y1-y2)*(y1-y2)); 13 } 14 int fa[maxn]; 15 int find(int x){ 16 if(fa[x]==x) return x; 17 int root=find(fa[x]); 18 fa[x]=root; 19 return root; 20 } 21 void link(int x,int y){ 22 int fx=find(x),fy=find(y); 23 if(fx!=fy){ 24 fa[fx]=fy; 25 } 26 } 27 bool check(int x,int y){ 28 int fx=find(x),fy=find(y); 29 if(fx!=fy) return false; 30 return true; 31 } 32 int l,n; 33 struct node{ 34 int x,y; 35 }nd[maxn]; 36 void init(){ 37 int pos=0; 38 scanf("%d%d",&n,&l); 39 for(int i=1;i<=n+2;i++) fa[i]=i;//n+1是上,n+2是下 40 for(int i=1;i<=n;i++){ 41 scanf("%d%d",&nd[i].x,&nd[i].y); 42 } 43 for(int i=1;i<=n;i++){ 44 e[++pos]=(eage){i,n+1,l-nd[i].y}; 45 e[++pos]=(eage){i,n+2,nd[i].y}; 46 for(int j=i+1;j<=n;j++){ 47 e[++pos]=(eage){i,j,dis(nd[i].x,nd[i].y,nd[j].x,nd[j].y)}; 48 } 49 } 50 int cnt=0; 51 sort(e+1,e+pos+1,cmp); 52 for(int i=1;i<=pos;i++){ 53 int u=e[i].u,v=e[i].v; 54 if(check(u,v)) continue; 55 link(u,v); 56 cnt++; 57 if(find(n+1)==find(n+2)){//只要上底和下底连接了就行 这样才能保证极大值可以通过 58 //如果后面更大,那这里是过不了的 59 printf("%.3f",e[i].dist); 60 break; 61 } 62 } 63 } 64 int main(){ 65 init(); 66 67 return 0; 68 }