MST (Kruskal Prim)

来源:互联网 发布:windows media 解码器 编辑:程序博客网 时间:2024/05/21 14:53

kruskal 需要对边集排序,所以只存储边的信息

#define E 100#define V 100#include<iostream>#include<algorithm>using namespace std;struct edge{int from=-1;int to=-1;int w=0;};edge edg[E];int vnum, edgenum;int cnt = 0;void add(int u, int v, int w,edge* e) {e[cnt].to = v;e[cnt].w = w;e[cnt].from = u;cnt++;}bool cmp(edge a, edge b) {return a.w < b.w;}void uni(int i, int j,int * fa) {int k = 1;if (i < j) {while (fa[k] != 0) {     //起始结束值,初始值,循环条件if (k!=i&&fa[k] == fa[i]) fa[k] = fa[j];k++;}fa[i] = fa[j];   //传递 fa[j]}else {while (fa[k] != 0) {if (k!=j&&fa[k] == fa[j]) fa[k] = fa[i];k++;}fa[j] = fa[i];    //保存fa[i]的值,去寻找他的等价类元素}}edge* MST_kruskal(edge *e,edge* kru) {int set[V] = { 0 }, fa[V] = { 0 };   //注意默认值为0 or 为-1for (int i = 1; i <= vnum; i++) {set[i] = i;fa[i] = i;}sort(e, e + cnt, cmp);cnt = 0;for (int i = 0; e[i].w != 0; i++) {if (fa[e[i].from] != fa[e[i].to]) {      //只与集合有关,与方向无关uni(e[i].from,e[i].to,fa);add(e[i].from, e[i].to, e[i].w, kru);}}return kru;}int main() {cin >> vnum>>edgenum;for(int k=0;k<edgenum;k++) {int i, j, w;cin >> i >> j >> w;add(i, j, w, edg);}edge res[V];MST_kruskal(edg, res);for (int i = 0; res[i].from!=-1; i++) {    //i++后先判断条件,再执行,执行完并不判断条件,直接++cout << res[i].from << "  " << res[i].to << "  " << res[i].w << endl;}return 0;}
Prim

从0号节点开始进入循环,循环n-1次(MST n-1条边),先初始化vis,lowcost,minc,并用0号节点赋值

vis保存节点是否被加入生成树中

lowcost维护的是(MST外)第i号节点到生成树的最小距离,只要把一个节点p加入生成树中,就使用cost[p][j]更新与p相邻接的所有树外j节点的lowcost值,不断更新,保证lowcost树外点到树的最小距离

下一次循环就选择离树最近的点,加入树并更新其他节点的lowcost值

#include<iostream>using namespace std;const int inf=0x3f3f3f3f;const int MAXN = 100;bool vis[MAXN];int lowcost[MAXN],vertexnum,edgenum,w[MAXN][MAXN];int MST_Prim(int cost[][MAXN], int n) {     //weight matrix and vertex numberint res = 0;for (int i = 0; i < n; i++) {lowcost[i] = inf;vis[i] = false;}int minc = inf,p;for (int i = 0; i < n; i++) {lowcost[i] = cost[0][i];}vis[0] = true;   //第一次循环的初始化for (int i = 1; i < n; i++) {   //n个点,MST有n-1条边minc = inf, p = -1;for (int j = 0; j < n; j++) {if (!vis[j] && lowcost[j] < minc) {minc = lowcost[j];p = j;}}if (minc == inf) return -1;vis[p] = true;res = res + minc;for (int j = 0; j < n; j++) {if (!vis[j] && lowcost[j] > cost[p][j]) {lowcost[j] = cost[p][j];}}}return res;}int main() {cin >> vertexnum >> edgenum;for (int i = 0; i < vertexnum; i++)for (int j = 0; j < vertexnum; j++)w[i][j] = inf;while (edgenum--) {int i, j, k;cin >> i >> j >> k;w[i-1][j-1] = k;w[j-1][i-1] = k;}int ans = MST_Prim(w, vertexnum);cout << ans;return 0;}
Prim算法以点为考虑对象,找到离树最近的树外点

Kruskal以边为考虑对象,找到连接树和树外的权值最小的边

Prim以点找边,所以有方向,如果无向图,则需要添加w[i][j]和w[j][i],否则找不到边

而Kruskal按权值排序找边,无关方向,若为有向图需考虑是否是from点树内,to树外


---------测试数据-----------

9
14
1 2 4
1 8 8
2 8 11
2 3 8
3 4 7
4 5 9
5 6 10
6 7 2
7 8 1
8 9 7
7 9 6
3 9 2
3 6 4
4 6 14

from CLRS Chap23



0 0
原创粉丝点击