最小生成树
最小生成树MST是在一个图中求出一个连接N个点的树,使得树的N-1条边的权值之和最小。
求最小生成树有两种方法:1. prim算法 2.kruskal算法
prim算法
贪心思想,将N个点分为两个集合。V(在最小生成树中的点集合)和S-V(不在最小生成树中的点集合),每次从S-V集合中选取 距离集合V中的点的距离最小的点,加入V集合。直到集合S-V为空。
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | struct Edge{ int vertex; int dist; Edge( int v, int d) : vertex(v), dist(d){}; }; vector<vector<Edge> > gGraph; struct Compare{ bool operator ()( const Edge& e1, const Edge& e2){ return e1.dist > e2.dist; } }; bool gVisited[MAX_NODE]; int Prim( int n){ //prim算法加堆优化 memset(gVisited, false , sizeof (gVisited)); //随便选择一个起点,假设从0开始 Edge e(0, 0); int sum_mst = 0; priority_queue<Edge, vector<Edge>, Compare> pq; pq.push(e); while (!pq.empty()){ e = pq.top(); pq.pop(); if (gVisited[e.vertex]) continue ; gVisited[e.vertex] = true ; sum_mst += e.dist; for ( int i = 0; i < gGraph[e.vertex].size(); i++){ //将该点连接边都加入到优先队列中,进行下一轮选择 pq.push(gGraph[e.vertex][i]); } } return sum_mst; } |
kruskal算法
贪心思想。将所有的边进行排序,然后按照边长从小到大的顺序,判断边连接的两点是否已经同时在最小生成树上了,若在,则抛弃该边(为了避免形成环),继续;否则将该边加入最小生成树。
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | //边的数据结构 struct Edge{ int from ; int to; double dist; Edge( int f, int t, double d) : from (f), to(t), dist(d){}; }; vector<Edge> gEdges; //用并查集来判断加入一条边是否会构成环 int gRoot[MAX_NODE]; int GetRoot( int c){ if (gRoot[c] != c){ gRoot[c] = GetRoot(gRoot[c]); } return gRoot[c]; } bool SameRoot( int c1, int c2){ int p1 = GetRoot(c1); int p2 = GetRoot(c2); return p1 == p2; } void Union( int c1, int c2){ int p1 = GetRoot(c1); int p2 = GetRoot(c2); gRoot[p1] = p2; } //用于对边进行排序 bool Compare( const Edge& e1, const Edge& e2){ return e1.dist < e2.dist; } double Kruskal( int s, int n){ double result; for ( int i = 0; i < n; i++){ gRoot[i] = i; } sort(gEdges.begin(), gEdges.end(), Compare); //无向图的边只存储了 从序号较小的节点指向序号较大的节点 int count = 0; for ( int i = 0; i < gEdges.size(); i++){ Edge& e = gEdges[i]; if (SameRoot(e. from , e.to)) continue ; count++; if (count == n - s){ //从最小生成树中的n-1条边,去掉最大的s-1条边(因为有s个卫星站,相当于s个点,则s-1条边) //,剩下的n-1-s条边中,最大的边长即为所求 result = e.dist; return result; } Union(e.to, e. from ); //gRoot[gRoot[e.to]] = gRoot[e.from]; //注意合并的时候,将 to 的根更新为 from的根。因为所有的边只存储了从小序号指向大序号 } return 0; } |
· C#高性能开发之类型系统:从 C# 7.0 到 C# 14 的类型系统演进全景
· 从零实现富文本编辑器#3-基于Delta的线性数据结构模型
· 记一次 .NET某旅行社酒店管理系统 卡死分析
· 长文讲解 MCP 和案例实战
· Hangfire Redis 实现秒级定时任务,使用 CQRS 实现动态执行代码
· C#高性能开发之类型系统:从 C# 7.0 到 C# 14 的类型系统演进全景
· 管理100个小程序-很难吗
· 基于Blazor实现的运输信息管理系统
· 如何统计不同电话号码的个数?—位图法
· 聊聊四种实时通信技术:长轮询、短轮询、WebSocket 和 SSE