1)prim算法
算法思想:
1、设图G的顶点集为U,从集合U中任取一点a加入顶点集V中选,a点作为起始点。
2、在剩下的集合U中寻找一点b,使得b到集合V的权值最小,将b加入集合V
3、反复第2部直到所有的顶点加入集合V中,此时就得到一颗最小生成树
注:代码顶点编号为0~n-1
#include <iostream> #include <cstring> #include <cstdio> #include <cmath> using namespace std; #define maxn 1010 #define INF 0x3f3f3f3f int map[maxn][maxn]; int mincost[maxn]; int vis[maxn]; void setmap(int m) { int a,b,cost; memset(map,INF,sizeof(map)); for(int i=0;i<m;i++) { scanf("%d%d%d",&a,&b,&cost); if(cost<map[a][b]) map[a][b]=map[b][a]=cost; } } int prim(int n) { for(int i=0;i<n;i++) { mincost[i]=INF; vis[i]=0; } mincost[0]=0; int res=0; while(true) { int pos=-1; for(int i=0;i<n;i++) if(!vis[i] && (pos==-1 || mincost[i]<mincost[pos])) pos=i; if(pos==-1) break; vis[pos]=1; res+=mincost[pos]; for(int i=0;i<n;i++) if(!vis[i] && mincost[i]>map[pos][i]) mincost[i]=map[pos][i]; } return res; } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { setmap(m); cout<<prim(n)<<endl; } return 0; }
2)Kruskal算法
算法思想:
1、将所有的边的权值按从小到大排序
2、遍历边,判断边的顶点是否在同一个集合中,如果不在同一个集合,将顶点并在一起,直到所有的顶点在同一个集合中,这是将得到一颗最小生成树
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; #define maxn 1010 struct edge { int x,y,cost; }; edge e[maxn]; int father[maxn]; bool cmp(edge a,edge b) { return a.cost<b.cost; } void init(int n) { for(int i=0;i<=n;i++) father[i]=i; } int getfather(int x) { if(x!=father[x]) father[x]=getfather(father[x]); return father[x]; } void Union(int x,int y) { x=getfather(x); y=getfather(y); father[y]=x; } int same(int x,int y) { return getfather(x)==getfather(y); } void setmap(int m) { for(int i=0;i<m;i++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].cost); } int kruskal(int n,int m) { sort(e,e+m,cmp); init(n); int res=0; for(int i=0;i<m;i++) { if(!same(e[i].x,e[i].y)) { Union(e[i].x,e[i].y); res+=e[i].cost; } } return res; } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { setmap(m); cout<<kruskal(n,m)<<endl; } return 0; }