最小生成树 Kruskal和Prim算法
算法过程:
1.将图中所有的边按照权值进行排序。
2.将图中的每一条边进行遍历,找出权值最小的边(注意:不能与已经加入到最小生成树集合的边构成环),如果符合要求,则把该边加入到最小生成树的集合中。
3.重复步骤2,添加一个计数器,直到边的数量为n-1的时候跳出循环,算法结束。
#include <bits/stdc++.h> #define maxn 1005 using namespace std; int pre[maxn]; //定义并查集数组 int sum ; //最小权值和 int _cout; struct edge //用结构体定义边,包括两个点和权值 { int u; int v; int w; }; edge e[maxn]; //定义边的个数 //并查集代码 int Find(int x) { int r =x; while(pre[r] != r) r = pre[r]; int i=x,j; while(i != r) { j =pre[i]; pre[i] = r; i = j; } return r; } int join(int x,int y) { int fx = Find(x); int fy = Find(y); if(fx != fy) { pre[fx] = fy; return 1; } return 0; } bool cmp(edge a, edge b) { return a.w<b.w; //按照从小到大的顺序进行排列 } int main() { int n,m;//n表示结点的个数,m表示给出的信息量(包含每一条边(u,v)的权值) while(scanf("%d %d",&n,&m) == 2) { sum = 0; _cout = 0; memset(e,0,sizeof(e)); memset(pre,0,sizeof(pre)); for(int i=1;i<=m;i++) scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w); sort(e+1,e+m+1,cmp); //sort函数是左闭右开 for(int i=1;i<=n;i++) pre[i] = i; // 初始化并查集数组 for(int i=1;i<=m;i++) //对每一条边进行处理 { if(join(e[i].u , e[i].v)){ _cout ++ ; //每次成功合并两个点,就会生成一条边,统计边的数量 sum += e[i].w; } if(_cout == n-1) break; } printf("%d\n",sum); } return 0; }
Prim算法:
此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。
Prim算法从任意一个顶点开始,每次选择一个与当前顶点集最近的一个顶点,并将两顶点之间的边加入到树中。Prim算法在找当前最近顶点时使用到了贪心算法#include <bits/stdc++.h> #define MAX 0x3f3f3f3f using namespace std; int logo[1010];//用0和1来表示是否被选择过 int map1[1010][1010]; int dis[1010];//记录任意一点到这一点的最近的距离 int n,m; int prim() { int i,j,now; int sum=0; for(i=1;i<=n;i++)//初始化 { dis[i]=MAX; logo[i]=0; } for(i=1;i<=n;i++) { dis[i]=map1[1][i]; } dis[1]=0; logo[1]=1; for(i=1;i<n;i++)//循环查找 { now=MAX; int min1=MAX; for(j=1;j<=n;j++) { if(logo[j]==0&&dis[j]<min1) { now=j; min1=dis[j]; } } if(now==MAX)//防止不成图 { break; } logo[now]=1; sum=sum+min1; for(j=1;j<=n;j++)//填入新点后更新最小距离,到顶点集的距离 { if(logo[j]==0&&dis[j]>map1[now][j]) { dis[j]=map1[now][j]; } } } if(i<n) { printf("?\n"); } else { printf("%d\n",sum); } } int main() { while(scanf("%d%d",&m,&n)!=EOF)//n是点数 { if(m==0) { break; } memset(map1,0x3f3f3f3f,sizeof(map1));//map是邻接矩阵储存图的信息 for(int i=0;i<m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); if(c<map1[a][b])///防止出现重边 { map1[a][b]=map1[b][a]=c; } } prim(); } return 0; }