借鉴自:https://www.cnblogs.com/hxsyl/p/3290832.html
最小生成树prime算法讲解:https://www.cnblogs.com/aiyelinglong/archive/2012/03/26/2418707.html
先用prim求出最小生成树T,在prim的同时,
用一个矩阵maxd[u][v] 记录 在T中连结任意两点u,v的唯一的路中权值最大的那条边的权值.(有些拗口),
这是很容易做到的,因为prim是每次增加一个结点s, 在此需要保存节点和其父节点,
采用DP,则最大权值要么是新加入的边,要么是父节点到起始点的采用DP算出来的距离
//temp是将要加入集合的点(还没有加入),pre[temp]是temp的父结点
for(int j=1; j<=n; j++) if(vis[j]) maxd[temp][j] = maxd[j][temp] = max(mincost, maxd[pre[temp]][j]);
以下是POJ-1679的代码 就是一个次小生成树 模板题
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #define mem(a, b) memset(a, b, sizeof(a)) using namespace std; const int maxn = 10010, INF = 0x7fffffff; typedef long long LL; int graph[510][510], d[maxn], vis[maxn], maxd[510][510], pre[maxn]; int n, m; int prime(int s) { int temp, sum = 0; mem(vis, 0); for(int i=1; i<=n; i++) d[i] = graph[s][i], pre[i] = s; vis[s] = 1; d[s] = 0; for(int i=1; i<n; i++) { int mincost = INF; for(int j=1; j<=n; j++) { if(!vis[j] && mincost > d[j]) mincost = d[j], temp = j; } for(int j=1; j<=n; j++) if(vis[j]) maxd[temp][j] = maxd[j][temp] = max(mincost, maxd[pre[temp]][j]); vis[temp] = 1; sum += mincost; for(int j=1; j<=n; j++) { if(!vis[j] && d[j] > graph[temp][j]) d[j] = graph[temp][j], pre[j] = temp; } } // for(int i=1; i<=n; i++) // sum += d[i]; return sum; } int main() { int T; cin>> T; while(T--) { cin>> n >> m; for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) if(i == j) graph[i][j] = 0; else graph[i][j] = graph[j][i] = INF; for(int i=0; i<m; i++) { int u, v, w; cin>> u >> v >> w; graph[u][v] = graph[v][u] = w; } int sum = prime(1); int lsum = INF; for(int i=1; i<=n; i++) for(int j=i+1; j<=n; j++) { if(i != pre[j] && j != pre[i] && graph[i][j] != INF) //找到不在最小生成树里的边 (在最小生成树里的边 对于i和j一定其中一个是另一个的父结点) if(sum - maxd[i][j] + graph[i][j] < lsum) //更新生成树 直至找到次小生成树 lsum = sum - maxd[i][j] + graph[i][j]; } if(lsum == sum) cout<< "Not Unique!" <<endl; else cout<< sum <<endl; } return 0; }