Kruskal 找到最小生成树

什么是图的最小生成树(min span tree ,MST)

对于有N个节点的图,边数最多 有 N*(N-1)/2 , 如果只是希望所有节点都连通, N-1条边就够了
所谓最小生成树指的是在所有N-1条边的连通图中,边的权值和最小的就是最小生成图

Kruskal 寻找最小生成图

  1. 所有边进行排序 ,得到边的序列 [10,20,30,40,80,90,91, 100]
  2. 取 [10] 这条边 , 1--4
  3. 取 [20] 这条边 , 1--4--2
  4. 取 [30] 这条边 , 1--4--2--5
  5. 取 [40] 这条边 , 对于节点1 和 节点5 ,它们已经是一个连通块了 ,不应该取这条边
  6. 取 [80] 这条边 , 节点3 不在已经形成的连通块1--4--2--5, 这条表可以取

7.至此,总共取了4条边, 满足N-1条边的要求,最小生成图找到了,即边集合 {[10],[20] ,[30] [80] }

根据上面的分析如何快速判断两个节点是否位于一个连通块是关键
请查看本人所写 并查集 求连通图问题

OK,开始实际问题分析并给出C++代码

//see https://michael.blog.csdn.net/article/details/107796632
class dsu
{
	vector<int> f;
public:
	dsu(int n)
	{
		f.resize(n);
		for(int i = 0; i < n; ++i)
			f[i] = i;
	}
	void merge(int a, int b)
	{
		int fa = find(a);
		int fb = find(b);
		f[fa] = fb;
	}
	int find(int a)
	{
		int origin = a;
		while(a != f[a])
		{
			a = f[a];
		}
		return f[origin] = f[a];
	}
};


class Solution {
public:
    vector<vector<int>> findCriticalAndPseudoCriticalEdges(int N, vector<vector<int>>& connections) {
       //

	dsu u(N+1);
    	sort(connections.begin(), connections.end(),[&](auto a, auto b){
    		return a[2] < b[2];//距离短的边优先
    	});
    	int edge = 0, p1, p2, dis, total = 0;
    	for(int i = 0; i < connections.size(); ++i)
    	{
    		p1 = connections[i][0];
    		p2 = connections[i][1];
    		dis = connections[i][2];
    		if(u.find(p1) != u.find(p2))//两个还未链接
    		{
    			u.merge(p1,p2);
    			edge++;
    			total += dis;
    		}
    		if(edge == N-1)
    			break;
    	}
    	auto MST= ( edge==N-1 ? total : -1);
        std::cout << MST;

         return {};
    }
};

题目描述

  1. 找到最小生成树里的关键边和伪关键边
    给你一个 n 个点的带权无向连通图,节点编号为 0 到 n-1 ,同时还有一个数组 edges ,其中 edges[i] = [fromi, toi, weighti] 表示在 fromi 和 toi 节点之间有一条带权无向边。最小生成树 (MST) 是给定图中边的一个子集,它连接了所有节点且没有环,而且这些边的权值和最小。

请你找到给定图中最小生成树的所有关键边和伪关键边。如果从图中删去某条边,会导致最小生成树的权值和增加,那么我们就说它是一条关键边。伪关键边则是可能会出现在某些最小生成树中但不会出现在所有最小生成树中的边。

请注意,你可以分别以任意顺序返回关键边的下标和伪关键边的下标。

posted @ 2021-05-21 16:54  boyang987  阅读(82)  评论(0编辑  收藏  举报