ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 图的最小生成树 最小生成树(Minimum Spanning Tree)是在给定无向图 G(V,E) 中求一棵树 T,使得 T 包含所有 V,且 T 的所有边都来自 E,并且满足整棵树的边权之和最小。 ## prim 算法 稠密图效果更佳。 ### 伪码 ```c++ Prim(G,d[]){ init; for(n){ u=使 d[u]最小的还未被访问的顶点标号; 记 u 已被访问; for(从 u 出发所能到达的顶点 v){ if(v 未被访问 && 以 u 为中介点使得 v 与集合 S 的最短距离 d[v] 更优) 将 G[u][v] 赋值给 v 与集合 S 的最短距离 d[v]; } } } ``` ### 邻接矩阵 ```c++ const int maxv=1000; const int inf=0x3fffffff; bool vis[maxv]={false}; int d[maxv]; int prim(){ fill(d,+maxv,inf); d[0]=0; int ans=0; for(int i=0;i<n;i++){ int u=-1,min=inf; for(int j=0;j<n;j++){ if(vis[j]==false && d[j]<min){ u=j; min=d[j]; } } if(u==-1) return -1; vis[u]=true; ans+=d[u]; for(int v=0;v<n;v++){ if(vis[v]==false && G[u][v]!=inf && G[u][v]<d[v]) d[v]=G[u][v]; } } return ans; } ``` ### 邻接表 ```c++ const int maxv=1000; vector<Node> Adj[maxv]; bool vis[maxv]={false}; int d[maxv]; int Prim(){ fill(d,d+maxv,inf); d[0]=0; int ans=0; for(int i=0;i<n;i++){ int u=-1,min=inf; for(int j=0;j<n;j++){ if(vis[u]==false && d[j]<min){ u=j; min=d[j]; } } if(u==-1) return -1; vis[u]=true; ans+=d[u]; for(int j=0;j<Adj[u].size();j++){ int v=Adj[u][j].v; int dis=Adj[u][j].dis; if(vis[v]==false && dis<d[v]) d[v]=dis; } } return ans; } ``` ## kruskal 算法 稀疏图效果更佳。 ### 伪码 ```c++ int kruskal(){ 令最小生成树的边权之和为 ans、最小生成树的当前边数为 num; 将所有边按边权从小到大排序; for(从小到大枚举所有边){ if(当前测试边的两个端点在不同的连通块中){ 将该测试边加入最小生成树中; ans+=测试边的边权; num++; if(num==顶点数-1) break; } } return ans; } ``` ### C++ 实现 ```c++ const int maxv=1000; struct edge{ int u,v; // 边的两端点 int cost; // 边权 }E[maxv]; bool cmp(edge a, edge b){ return a.cost<b.cost; } int father[N]; // 并查集 int findFather(int x){ } int kruskal(int n, int m){ // n=边数,m=顶点数 int ans=0, num=0; for(int i==1;i<=n;i++){ father[i]=i; // 并查集初始化 } sort(E,E,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++; if(num==n-1) break; } } if(num!=n-1) return -1; else return ans; } ```