一、“换边”算法
用Kruskal求最小生成树,标记用过的边。求次小生成树时,依次枚举用过的边,将其去除后再求最小生成树,得出所有情况下的最小的生成树就是次小的生成树。可以证明:最小生成树与次小生成树之间仅有一条边不同。
这样相当于运行m次Kruskal算法。
复杂度O(m^2)
示例代码:
int Kruskal_MinTree() { int u,v; init(); int i,flag,cnt; minedge = 0; flag = cnt = 0; int tmp = 0; for(i=0;i<m;i++) { u = edge[i].s; v = edge[i].t; int fx = findset(u); int fy = findset(v); if(fx != fy) { use[minedge++] = i; tmp += edge[i].w; fa[fx] = fy; cnt++; } if(cnt == n-1) { flag = 1; //找到最小生成树 break; } } if(flag) return tmp; return -1; //不存在最小生成树,返回-1 } int Sec_MinTree() { int i,j,mini,tmp; int cnt,flag,u,v; mini = Mod; for(i=0;i<minedge;i++) //枚举最小生成树中的每条边,将其去除 { init(); flag = cnt = tmp = 0; for(j=0;j<m;j++) { if(j != use[i]) //去除边 { u = edge[j].s; v = edge[j].t; int fx = findset(u); int fy = findset(v); if(fx != fy) { cnt++; tmp += edge[j].w; fa[fx] = fy; } if(cnt == n-1) { flag = 1; break; } } } if(flag && tmp < mini) mini = tmp; } if(mini == Mod) mini = -1; return mini; }