图论:非严格次小生成树

参考博客:这位大佬写的很详细

#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;
}

猜你喜欢

转载自blog.csdn.net/qq_45695839/article/details/106629528
今日推荐