lixiaotao 2020-06-06
最小生成树 kruskal 算法,适用于边稀疏的图,
先按照边进行排序。
取出小的边
选出小的,判断边的两个顶点是否是同一连通分量。如果是则继续取出下一个边。否则输出两个顶点,并合并两个连通分量。
需要注意的是一开始需要一个辅助数组来记录连通分量,初始化所有顶点自己是一个连通分量。当合并两个连通分量时,需要遍历这个数组,将其中一个设置成另一个连通分量的值。
struct Edge{ int head; int tail; int lowcost; }; bool compare(const Edge& e1, const Edge& e2) { return e1.lowcost < e2.lowcost; } void MiniSpanTree_Kruskal(vector<vector<int> > G) { int m = G.size(); vector<Edge> edge; vector<int> Vex(m);//连通分量 //将图转成边存储 for(int i = 0;i<m;i++){ Vex[i] = i;//初始连通分量为其自身 for(int j = 0;j<m;j++){ if(j == i || G[i][j] == -1) continue; Edge e; e.head = i; e.tail = j; e.lowcost = G[i][j]; edge.push_back(e); } } sort(edge.begin(),edge.end(),compare); for(int i = 0;i<edge.size();i++){ int v0 = edge[i].head, v1 = edge[i].tail; if(Vex[v0] == Vex[v1]) continue; // 如果v0和v1是同一个连通分量,就找下一个 cout<<v0<<v1; int temp = Vex[v1]; for(int j = 0;j<m;j++){ if(Vex[j] == temp) { Vex[j] = Vex[v0]; //更新v1的连通分量,并入到v0 } } } }
一颗有n个顶点的生成树有且仅有n-1条边,如果生成树中再添加一条边,则必定成环。此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。