图算法之最小生成树
1. 对于一个无向连通图G=(V,E),若存在一个无回路的子集TE,它连接了所有的顶点,切其权值之和:
2. Kruskal算法
伪代码如下:
MST_KRUSKAL(G,w)
A = {}
for vertex in V
do make-set(v)
sort the edges based on weight
for edge(u,v) in E taken by nonincreasing order by weight
do if find_set(u) != find_set(v)
then A = A U {(u,v)}
union(u,v)
return A
大致思想是先将边按权值排序,按顺序取边,如果该边的两个节点不处于同一集合,说明该边未加入到子集中,则将边加入子集,将两个节点并入同一集合中。
3. Prim算法
Prime算法的思想是将图中端点分为两个集合,集合A中的是已访问过的节点,集合B中是仍未访问的节点,每次寻找能将两个集合连接起来的权值最小的边,伪代码如下
MST_PRIM(G,w,r) //r表示起始节点
for each u in V
do key[u] = INF
parent[u] = NIL
key[r] = 0
Q = V
while Q!={}
do u = extract_min(Q)
for v in Adj[u]
do if v in Q and w(u,v)<key[v]
then parent[v] = u
key[v] = w(u,v)
4. C++代码
Kruskal算法
#include <iostream> #include <vector> #include <map> #include <fstream> using namespace std; #define maxn 1000 int nodes,edges; int father[maxn]; int graph[maxn][maxn]; int weight[maxn][maxn]; bool visited[maxn]; multimap<int,pair<int,int>> weight_edge; //以边的权重为键,边的两个点为值。 vector<pair<int,int>> result; void make_set(int i) { father[i] = i; } int find_set(int i) { return father[i]; } void _union(int i,int j) { int temp = father[j]; for(int m =1;m<=nodes;m++) //遍历所有节点,将父节点为father[j]的节点的父节点更新为father[i],即归为同一个集合 if(father[m] == temp) father[m] = father[i]; } void mst_kruskal() { for(int i=1;i<=nodes;i++) make_set(i); multimap<int,pair<int,int>>::iterator map_it = weight_edge.begin(); while(map_it !=weight_edge.end()) { int _first,_second; _first = map_it->second.first; _second = map_it->second.second; if(find_set(_first) != find_set(_second)) //不在一个集合中 { result.push_back(make_pair(_first,_second)); _union(_first,_second); map_it++; } else map_it++; } } int main() { ifstream graph_data; graph_data.open("graph.txt"); graph_data>>nodes>>edges; for(int i=0;i<edges;i++) { int first,second,temp_weight; graph_data>>first>>second>>temp_weight; graph[first][second] = 1; graph[second][first] = 1; //无向图 weight[first][second] = temp_weight; weight[second][first] = temp_weight; weight_edge.insert(make_pair(temp_weight,make_pair(first,second))); //插入map中 } memset(visited,false,sizeof(visited)); mst_kruskal(); for(int i=0;i<result.size();i++) { int m,n; m = result[i].first; n = result[i].second; cout<<m<<"->"<<n<<" "<<weight[m][n]<<endl; } return 0; }