数据结构--图(更新中)
摘抄于胡凡的《算法笔记》
一.最小生成树(Minimum Spanning Tree):在一个给定的无向图G中求一棵树T,使得这棵树拥有图G中的边,并且满足整棵树的边权之和最小。
算法核心思想:贪心
1.Krustal算法(边贪心)
(1)对所有的边按边权从小到大进行排序;
(2)按边权从小到大测试所有边,如果当前测试边所连接的两个顶点不在同一个连通块中,则把这条测试边加入当前最小生成树中;否则,将边舍弃;
(3)执行步骤2,直到最小生成树中的边数等于总顶点数减1或是测试完所有边时结束。如果结束时,最小生成树的边数小于总顶点数减1,说明该图不连通。
判断两个顶点是否在一个连通块中需要用到并查集,查看其根节点是否是同一个,若不是同一个则合并到一个集合中,否则舍弃。
核心代码展示:
#define MAXE 100 struct Edge{ int u,v; int cost; }E[MAXE];
bool cmp(Edge a,Edge b) { return a.cost<b.cost; } int Father[100];//并查集数组 //查找根节点 int FindFather(int x) { if(x!=Father[x]) return FindFather(Father[x]); return x; } //Krustal函数返回最小生成树的边权之和,参数n为顶点个数,m为图的边数 int krustal(int n,int m) { //ans为所求边权之和,Num_Edge为当前生成树的边数 int ans=0,Num_Edge=0; //并查集初始化 for(int i=1;i<=n;++i) Father[i]=i; //所有的边按边权从小到大排序 sort(E,E+m,cmp); for(int i=0;i<m;++i) { //查询测试边两个端点所在集合的根节点 int faU=FindFather(E[i].u); int faV=FindFather(E[i].v); if(faU!=faV){ Father[faU]=faV; ans+=E[i].cost; Num_Edge++; if(Num_Edge==n-1) break; } } //不是连通的 if(Num_Edge!=n-1) return -1; else return ans; }
时间复杂度:O(ElogE) 其中E为图的边数
算法是用于顶点多,边数少的情况。
2.Prim算法
基本思想:对图G(V,E)设置集合S,存放已被访问的顶点,然后每次从集合V-S中选择与集合S的最短距离最小的一个顶点(记为u),访问并加入集合S,之后令u为中介点,优化所有的从u你能到达的顶点v与集合S之间的最短距离。这样的操作执行n次(n为顶点个数),直到集合S已包含所有顶点。
伪代码:
G为图,一般设为全局变量;数组d为顶点与几何S的最短距离 Prim(G,d[]){ 初始化; for(循环n次){ u=使d[u]最小的还未被访问的顶点的标号; 记u已被访问; for(从u出发能到达的所有顶点v){ if(v未被访问过&&以u为中介点使得v与集合S的最短距离d[v]更优){ 将G[u][v]赋值给v与集合S的最短距离d[v]; } } } }