最小生成树:在无向图中,连接所有的点,不形成环,使所有的边权值和最小的树
算法有:prim算法: dijkstra算法类似(dis[i]的含义不同,dijkstra中是起点,prim中是已经访问过的所有点) 稠密图时使用 O(V^2)
kruskal算法:并查集思想,每次都找到最小的边,判断这两个边连接的点是不是在同一个集合中,如果不是就连接起来 稀疏图时使用 O(ElogE)
struct node{ int v,dis; node(int _v,int _dis) : v(_v),dis(_dis){} }; vector<node> adj[maxn]; int dis[maxn],vis[maxn]; int n,m,st,ed; void prim(int st){ //树的总权值,以及当前所有的连接好了的边 for(int i=0;i<n;i++){ int u=-1,mini=INF; //与dijkstra是不是超级像!!!!! for(int j=0;j<n;j++){ if(mini>dis[j]&&vis[j]==0) { mini=dis[j]; u=j; } } if(u==-1) return; vis[u]=1; ans+=dis[u]; //!!!!!啊啊啊记住这个 for(int j=0;j<adj[u].size();j++){ int id=adj[u][j].v; int diss=adj[u][j].dis; if(!vis[id]&&dis[id]>diss){ dis[id]=diss;//!!!! } } } }
kruskal
struct edge{ int from,to; int dis; }E[maxn]; int fa[maxn]; int findfather(int x){ if(x!=fa[x]) return findfather(fa[x]); return fa[x]; } bool cmp(edge a,edge b){ return a.dis<b.dis; } void kruskal(int n,int m){ //n是顶点数,m是边数 for(int i=0;i<n;i++) fa[i]=i; //先弄这个 fill(dis,dis+maxn,INF); memset(vis,0,sizeof(vis)); dis[0]=0; int ans=0,numedge=0; //这里才有!!总的权值和现在有了的边 sort(E,E+m,cmp); //对边进行排序 for(int i=0;i<m;i++){ int fa1=findfather(E[i].from); int fa2=findfather(E[i].to); if(fa1!=fa2){ fa[fa2]=fa1; numedge++; ans+=E[i].dis; if(numedge==n-1) break; //!!!!!!!如果边数已经够了的话就可以break了 } } if(numedge!=n-1) { cout<<"error no liantong"<<endl; return; } else{ cout<<ans<<endl; return; } }