1.prim
假设有一颗只包含一个顶点v的树T。然后贪心地选取T和其他顶点之间相连的最小权值的边,并把它加到T中。不断进行这个操作,就可以得到最小生成树。
#include<iostream> using namespace std; #define INF 10000000 const int maxv=1005; int V,E,start; int cost[maxv][maxv]; int mincost[maxv]; int used[maxv]; int prim() { for(int i=0;i<V;i++) { mincost[i]=INF; used[i]=0; } mincost[0]=0; int res=0; while(true) { int v=-1; //从不属于x的顶点中选取从x到其权值最小的顶点 for(int u=0;u<V;u++) { if(!used[u]&&(v==-1||mincost[v]>mincost[u])) v=u; } if(v==-1) break; used[v]=1; res+=mincost[v]; for(int u=0;u<V;u++) { mincost[u]=min(mincost[u],cost[v][u]); } } return res; } int main() { cin>>V>>E; int from,to,value; for(int i=0;i<V;i++) { for(int j=0;j<V;j++) { cost[i][j]=INF; } } for(int i=0;i<E;i++) { cin>>from>>to>>value; cost[from][to]=value; } cout<<prim()<<endl; }
2.kruskal
按照边的权值的顺序从小到大查看一遍,如果不产生圈,就把当前这条边加入到生成树中。先理解并查集就很好理解了。
//克鲁斯卡尔(Kruskal)算法因为只与边相关,则适合求稀疏图的最小生成树。而prime算法因为只与顶点有关,所以适合求稠密图的最小生成树 #include<iostream> #include<algorithm> using namespace std; const int maxn=1005; const int maxe=10005; struct edge { int from,to,cost; edge(){} edge(int ff,int tt,int cc) { from=ff; to=tt; cost=cc; } }; bool cmp(edge e1,edge e2) { return e1.cost<e2.cost; } int V,E; edge es[maxe]; //并查集 int rank[maxn]; int par[maxn]; void init(int x) { for(int i=0;i<x;i++) { par[i]=i; rank[i]=0; } } int find(int x) { if(par[x]==x) return x; else return par[x]=find(par[x]); } void unite(int x,int y) { x=find(x); y=find(y); if(x==y) return; if(rank[x]<rank[y]) par[x]=y; else { par[y]=x; if(rank[x]==rank[y]) rank[x]++; } } bool same(int x,int y) { return find(x)==find(y); } int kruskal() //n为边的数量 { sort(es,es+E,cmp); init(V); //并查集的初始化 int res=0; for(int i=0;i<E;i++) { edge e=es[i]; if(!same(e.from,e.to)) { unite(e.from,e.to); res+=e.cost; } } return res; } int main() { cin>>V>>E; int from,to,value; for(int i=0;i<E;i++) { cin>>from>>to>>value; es[i]=edge(from,to,value); } cout<<kruskal()<<endl; return 0; }