一、算法步骤:
严格次小生成树的求法:
1、用kruskal算法求出最小生成树,标记树边和非树边,再建图。
2、dfs出所有的以a为起点到其它点的最长边d1[a, b]和次长边d2[a, b],是严格的最长和次长
3、依次枚举非树边,求min(sum + w - dist[a][b])
二、证明:
前提:
kruskal算法正确 (1)
最长边d1[a, b]和次长边d2[a, b],是严格的最长和次长 (2)
命题1: 对于非树边:(u,v,w),证明一定有:
反证法:,(1)不成立,矛盾,所以一定是
命题2:对于非树边:(u,v,w), 证明一定有:
反证法:,
(2),
(1)错误,矛盾。
得到结论:
(3)
(4)
所以对于每一条非树边的长度,一定是满足(3)、(4),所以只要存在严格次小生成树,一定能求出来。ans = min(ans, s - d1[a, b]或者是d2[a, b] + c)
/*
严格次小生成树的求法:
1、用kruskal算法求出最小生成树,标记树边和非树边,再建图。
2、dfs出所有的以a为起点到其它点的最长边和次长边。
3、依次枚举非树边,求min(sum + w - dist[a][b])
dfs为什么要将初值赋值为inf?
因为当非树边等于最长边时,可能不存在相应的次长边来求ans,所以将初值赋值为inf,当求
ans的时候得到一个不可能的值。
*/
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 505, M = 10010 << 1, inf = 0x3f3f3f3f;
struct edge {
int a, b, w;
bool f;
bool operator< (const edge& W) const {
return w < W.w;
}
}eg[M];
int n, m, s;
int h[N], e[M], ne[M], w[M], idx;
int d1[N][N], d2[N][N];
int p[N];
int find(int x) {
if(x != p[x]) p[x] = find(p[x]);
return p[x];
}
void add(int a, int b, int c) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++;
}
void dfs(int u, int fa, int m1, int m2, int d1[], int d2[]) {
d1[u] = m1, d2[u] = m2;
for(int i = h[u]; ~i; i = ne[i]) {
int j = e[i], v = w[i];
int t1 = m1, t2 = m2;
if(j == fa) continue;
if(v > t1) t2 = t1, t1 = v;
else if(v > t2 && v != t1) t2 = v; // 注意要求严格的次大最大生成树
dfs(j, u, t1, t2, d1, d2);
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
std::cin >> n >> m;
memset(h, -1, sizeof h);
for(int i = 1; i <= n; i ++ )
p[i] = i;
for(int i = 0; i < m; i ++ ) {
int x, y, z;
std::cin >> x >> y >> z;
eg[i] = {x, y, z, 0};
}
sort(eg, eg + m);
// for(int i = 0; i < m; i ++ )
// cout << eg[i].w << " \n"[i == m - 1];
for(int i = 0; i < m; i ++ ) {
int a = eg[i].a, b = eg[i].b, c = eg[i].w;
int pa = find(a), pb = find(b);
eg[i].f = 0;
if(pa == pb) continue;
s += c;
p[pa] = pb;
eg[i].f = 1;
add(a, b, c), add(b, a, c);
}
// dfs为什么要将初值赋值为inf?
// 因为当非树边等于最长边时,可能不存在相应的次长边来求ans,所以将初值赋值为inf,当求
// ans的时候得到一个不可能的值。
for(int i = 1; i <= n; i ++ )
dfs(i, -1, -inf, -inf, d1[i], d2[i]);
int ans = 1e18;
for(int i = 0; i < m; i ++ ) {
if(eg[i].f) continue;
int a = eg[i].a, b = eg[i].b, c = eg[i].w;
if(d1[a][b] < c) ans = min(ans, s + c - d1[a][b]);
else if(d2[a][b] < c) ans = min(ans, s + c - d2[a][b]);
}
std::cout << ans << endl;
return 0;
}