最小生成树
来源:互联网 发布:小米手环2 知乎 编辑:程序博客网 时间:2024/05/22 16:49
算法一:Prim算法(可称为加点法)
点集记为v。 定义一个集合U,来存储已经在生成树中的点。v-u是未在生成树中的点。定义一个closedge数组,分为两个区域,一个存储最小边在u中的顶点,另一个存储最小边的权值。将初始顶点加入U中,初始化closedge数组。选择最小边closedge[k],将K加入集合U,输出此边。更新closedge[]的值,选择集合V-U中点到k和u之间较小的哪个权值存到clodedge数组中。重复此步骤,直到所有的顶点都加入u中。
用邻接矩阵存储图,用一维数组存储现已有的树到其他定点的最小权值,用另一个一维数组存储某个点是否在生成树中。
#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>using namespace std;#define Maxn 110#define INF 9999999int maz[Maxn][Maxn],lowcase[Maxn],flag[Maxn];//maz[i][j]表示i到j的距离,注意无向图和重边!lowcase数组存的是现已在树里的点所能到达的点(Maxn)的最小权值//flag数组是用来标记某个点(Maxn)是否已经在树里面int prim(int n){ int i,j,ans = 0,pos,mi; memset(flag,0,sizeof(flag));//起初所有点都不在生成树中 for (i = 2; i <= n; ++i) lowcase[i] = maz[1][i];//先以1作为根节点,更新lowcase数组 lowcase[1] = 0;//为了数组里的值全(自己到自己的距离是0) flag[1] = 1;//1这个点(初始点)标记为已在树里面 for (i = 0; i < n-1; ++i)//循环n-1次,每次找一个点纳入到树里面,加上1根节点总共就是n个点 { mi = INF;//mi为每次在lowcase数组里找到的最小值,所以刚开始赋值成最大值 for (j = 1; j <= n; ++j)//寻找最小权值的点 { if (!flag[j] && lowcase[j] < mi)//j点不在树里面并且权值小 { mi = lowcase[j]; pos = j;//记录一下这个将要进入生成树的点 } } ans += mi;//记录最小生成树的总权值 flag[pos] = 1;//将此次寻找的点标记为已经加入生成树 for (j = 1; j <= n; ++j)//用新的节点更新lowcase数组 { if (!flag[j] && maz[pos][j] < lowcase[j])//判断新加入的点到其他所有未加入的点的距离是否比前一个点的小 { lowcase[j] = maz[pos][j];//如果小的话更新数组的值 } } } return ans;//返回最小生成树的总权值}int main(){ int n,i,j; while (~scanf("%d",&n) && n)//顶点个数 { for (i = 1; i <= n; ++i) { for (j = 1; j <= n; ++j) maz[i][j] = i == j ? 0 : INF;//用邻接矩阵存储图 }//刚开始得把数组里的数存成无穷大//本身到本身的距离是0//点和点之间的距离是无穷大 int a,b,c; for (i = 0; i < n*(n-1)/2; ++i)//最大边数 { scanf("%d%d%d",&a,&b,&c); if (c < maz[a][b]) maz[a][b] = maz[b][a] = c;//无向图+重边 } int ans = prim(n);//n个点的最小生成树的总长度 printf("%d\n",ans); } return 0;}
算法二:克鲁斯卡尔(加边法)
将所有边的权值排序。
1)初始状态看为只有顶点没有边,每一个顶点看作一个连通分量。
2)选择最小权值的边,如果该边连接了不同连通分量,则将该边加入集合T,否则舍去该边,继续寻找下一条权值最小的边。
3)重复2)直到所有顶点都在同一个连通分量中。
#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>using namespace std; #define Maxn 1100 int p[Maxn]; int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }//并查集 struct node { int u,v,w; };//每条边的情况,u,v是边的端点,w是边的权值 struct node q[Maxn*500]; //定义边的个数 int cmp(node a,node b) { return a.w < b.w; }//sort将边按权值排序 int main() { int n,m,sum,num,i,x,y; while (~scanf("%d",&n) && n) { for (i = 1; i <= n; ++i) p[i] = i;//初始化每个顶点是一个连通分量 m = n * (n-1) / 2; //最大边的数 for (i = 0; i < n*(n-1)/2; ++i) { scanf("%d%d%d",&q[i].u,&q[i].v,&q[i].w);//****不需要考虑重边的情况,因为重边的存在并不覆盖 //之前的边,重边参与排序,选出重边中最小的,就算遍历到了重边中较大的,此时端点已经在同 //一棵树中了,所以重边的存在不会有影响 } sort(q,q+m,cmp);//将边按照权值排序 sum = num = 0; for (i = 0; i < m; ++i)//m条边,从其中选出****n-1条边,然后跳出循环 { x = find(q[i].u); y = find(q[i].v); //判断两个顶点的边是否在同一个连通分量中 if (x != y) //不在同一个连通分量中 { if (x > y) p[x] = y; else p[y] = x;//连通分量标志合并到哪个较小的中去 sum += q[i].w; //记录生成树的总权值 ++num; //记录加入生成树中的边数 } if (num == n-1) //当足够了n-1条边的时候停止 break; } printf("%d\n",sum); //输出总权值 } return 0; }
0 0
- 最小比例 最小生成树
- 最小生成树&&次最小生成树
- 最小生成生成树计数
- 树+最小生成树
- 最小生成树
- 最小生成树 MST
- 最小生成树Kruskal
- kruskal 最小生成树
- 最小生成树
- 最小生成树
- 最小生成树
- 最小生成树
- 最小生成树 MST
- 最小生成树问题
- 最小生成树
- 最小生成树
- 最小生成树
- 最小生成树
- 递归于非递归的二分搜索法
- CSS3基础——背景
- docker save/load, export/import
- Android应用外网ip和地理位置解析
- C# 还是 VB.net ,语言选择
- 最小生成树
- bzoj1022: [SHOI2008]小约翰的游戏John
- linux常用命令
- 汉字按照字母排序
- 使用encodeURIComponent() 函数解决js传参的特殊字符问题
- 前端开源项目周报0228
- sublime Text3使用笔记
- Linux下Mongodb安装和启动配置
- 五大框架的学习过程中遇到的问题