最小瓶颈路
最小瓶颈路:
给定一个加权无向图,并给定无向图中两个结点u和v,求u到v的一条路径,使得路径上边的最大权值最小。
由定义可知,最小瓶颈路一定在最小生成树内。所以有一种方法可以求出最小瓶颈路,在已经生成的树内查找。时间复杂度是O(n),点比较多的时候就会占时间。还有一种方法,如果在建立最小生成树时就已经将各个点对的最小瓶颈树储存在数组中,时间复杂度会降到O(1)。先给出第一种方法的代码:
先将无根树变成有根树,下面是将无根树变为有根树的代码:
1 void build(int u, int fa) 2 { 3 int n = g[u].size(); 4 for(int i=0; i<n; i++){ 5 int v = g[u][i]; 6 if(v == fa) continue; 7 p[v] = u; 8 build(v, u); 9 } 10 } 11 int main() 12 { 13 int n, t, start; 14 scanf("%d", &t); 15 while(t--) { 16 for(int i=0; i<N; i++) 17 g[i].clear(); 18 scanf("%d%d", &n, &start); 19 int a, b; 20 for(int i=0; i<n-1; i++){ 21 scanf("%d%d", &a, &b); 22 g[a].push_back(b); 23 g[b].push_back(a); 24 } 25 p[start] = -1; 26 build(start, -1); 27 if(n >= 1) 28 printf("%d", p[1]); 29 for(int i=2; i<=n; i++) 30 printf(" %d", p[i]); 31 printf("\n"); 32 33 } 34 return 0; 35 }
将无根树变成有根树方便遍历。接下来就对点进行dfs。
1 void dfs(int v) 2 { 3 for ( int u = 1; u <= n; ++u ) 4 { 5 if(!done[u] && p[u] == v) // done检查是否被标记 , p是指v是不是u的父亲节点 6 { 7 done[u] = 1; 8 for ( int x = 1; x <= n; ++x ) 9 if (done[x] && x != u ) 10 { 11 maxbian[x][u] = maxbian[u][x] = max{maxbian[x][u],maxbian[u][v]}; 12 } 13 dfs(u); 14 } 15 } 16 }
核心步骤: maxbian[x][u] = maxbian[u][x] = max{maxbian[x][u],maxbian[u][v]};第二种法中也是一样;
第二种方法就分prim算法和kruskal算法
prim算法中,也无根树变成有根树的同时进行对点对的更替
1 int prim(int s) 2 { 3 int res=0; 4 memset(maxcost,0,sizeof(maxcost)); 5 for(int i=1;i<=n;i++) 6 vis[i] = 0, d[i] = INF, pre[i]=i; 7 8 d[s]=0; 9 for(int i=0;i<n;i++) 10 { 11 int maxx=INF, index=-1; 12 for(int j=1;j<=n;j++) 13 { 14 if(!vis[j]&&d[j]<maxx) 15 { 16 maxx=d[index=j]; 17 } 18 } 19 if(index==-1) 20 break; 21 22 for(int j=1;j<=n;j++) 23 if(vis[j]) 24 maxcost[index][j] = maxcost[j][index] = 25 max(maxcost[pre[index]][j], maxx); 26 27 res+=maxx; 28 vis[index]=1; 29 30 for(int j=1;j<=n;j++) 31 { 32 if(!vis[j]&&g[index][j]<d[j]) 33 { 34 d[j] = g[index][j]; 35 pre[j] = index; 36 } 37 } 38 } 39 return res; 40 }
部分代码转自http://blog.csdn.net/fuyukai/article/details/51321680