最小生成树概念:
给定一个无向图,如果它的某个子图中任意两个顶点都互相连通并且是一颗树,那么这棵树就称为生成树。如果边上有权值,那么使得边权和最小的生成树就叫做最小生成树(MST)。
常用算法:Prim 算法, Kruskal算法
Prim 算法
Prim算法与Dijkstra算法十分相似,基于贪心思想。
模板:
const int INF = 0x3f3f3f3f; int cost[MAX_V][MAX_V]; int mincost[MAX_V]; bool used[MAX_V]; int V; int prim(){ for(int i = 0; i < V; ++i){ mincost[i] = INF; used[i] = false; } mincost[0] = 0; used[0] = true; int res = 0; for(int i = 1; i < V; ++i){ int v = -1; for(int j = 0; j < V; ++j){ if(!used[j] && (v == -1 || mincost[j] < mincost[v])) v = j; } if(v == -1) return -1; // 图不连通 used[v] = true; res += mincost[v]; for(int j = 0; j < V; ++j){ if(!used[j] && mincost[j] > cost[v][j]) mincost[j] = cost[v][j]; } } return res; }
Kruskal 算法
模板:
const int INF = 0x3f3f3f3f; struct Edge{ int u, v, cost; }; bool comp(const Edge& e1, const Edge& e2){ return e1.cost < e2.cost; } Edge edge[MAX_E]; int f[MAX_V];// 并查集 int V, E; int Find(int x){ if(f[x] == - 1) return x; return f[x] = Find(f[x]); } int kruskal(){ for(int i = 0; i < MAX_V; ++i){ f[i] = -1; } sort(edge, edge + E, comp); int res = 0, cnt = 0; for(int i = 0; i < E; ++i){ Edge e = es[i]; int t1 = Find(e.u); int t2 = Find(e,v); if(t1 != t2){ res += e.cost; f[t1] = t2; ++cnt; } if(cnt == n - 1) break; } if(cnt < n - 1) return -1; // 不连通 else return res; }