参考博客:这位大佬写的很详细
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 1000 + 10, maxe = 1000 * 1000 / 2 + 5, INF = 0x3f3f3f3f;
int n, m;//n个点,m条边
int head[maxn];//并查集用
int Max[maxn][maxn];//Max[i][j]表示从i到j的权重最大的边
struct Edge {
int u, v, w;//u到v权重为w
bool vis;
}edge[maxe];//存边
vector<int> G[maxn];
bool cmp(const Edge &a, const Edge &b) {
return a.w < b.w;
}//kruscal对边的权重排序
void Init() {
for(int i = 1; i <= n; i ++) {
G[i].clear();
G[i].push_back(i);
head[i] = i;
}
}//初始化
int Find(int x) {
if(head[x] == x) return x;
return head[x] = Find(head[x]);
}//并查集合并
int Kruskal() {
sort(edge + 1, edge + 1 + m, cmp);
Init();
int ans = 0, cnt = 0;
for(int i = 1; i <= m; i ++) {
if(cnt == n - 1) break;//合并完成
int fx = Find(edge[i].u), fy = Find(edge[i].v);
if(fx != fy) {
cnt ++;
edge[i].vis = true;
ans += edge[i].w;
int len_fx = G[fx].size(), len_fy = G[fy].size();
for(int j = 0; j < len_fx; j ++){
for(int k = 0; k < len_fy; k ++){
Max[G[fx][j]][G[fy][k]] = Max[G[fy][k]][G[fx][j]] = edge[i].w;//因为已经对边排过序,所以后面的边权重>=前面的边
}
}
head[fx] = fy;//fx父节点是fy
for(int j = 0; j < len_fx; j ++)
G[fy].push_back(G[fx][j]);//fy能到达fx所能到达的点
}
}
return ans;
}
int Second_Kruskal(int MST) {
int ans = INF;
for(int i = 1; i <= m; i ++){
if(!edge[i].vis){
ans = min(ans, MST + edge[i].w - Max[edge[i].u][edge[i].v]);
//printf("%d %d %d %d\n",edge[i].w,edge[i].u,edge[i].v,Max[edge[i].u][edge[i].v]);
}
}
return ans;
}
int main() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= m; i ++) {
scanf("%d %d %d", &edge[i].u, &edge[i].v, &edge[i].w);
edge[i].vis = false;
}//读入边
int MST = Kruskal();
int Second_MST = Second_Kruskal(MST);
if(Second_MST>MST)
printf("%d\n", Second_MST );
else printf("请用严格次小生成树求解");
//printf("%d\n",MST);
/*for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
printf("%d ",Max[i][j]);
}
printf("\n");
}*/
return 0;
}