一个连通图的生成树是图的极小连通子图。它包含图中的所有顶点,并且只含尽可能少的边。若砍去它的一条边,就会使生成树变成非连通图;若给它增加一条边,则会形成一条回路。
最小生成树有如下性质:
1.最小生成树非唯一,可能有多个最小生成树;
2.最小生成树的边的权值之和总唯一,而且是最小的;
3.最小生成树的边数为顶点数减1。
构造最小生成树可以有多种算法。其中多数算法利用了最小生成树的下列一种简称为MST的性质:
假设N=(V,{E})是一个连通网,U是顶点集V的一个非空子集。若(u, v)是一条具有最小权值(代价)的边,其中u∈U,v∈V-U,则必存在一棵包含边(u, v)的最小生成树。
基于该性质的最小生成树算法主要有:prim算法和kruskal算法,它们都是基于贪心算法的策略。
源代码如下:
#include "stdio.h" typedef struct //图的邻接矩阵存储结构体定义 { int vexs[10]; int arcs[10][10]; int n, e; }MGraph; bool visit[10]; int pre[10]; void create(MGraph &G); //图的创建 void prim(MGraph G, int u); //prim算法 void kruskal(MGraph G, int *pre); //kruskal算法 int main() { int i; MGraph G; create(G); printf("最小生成树之prim算法路径:\n"); prim(G, G.vexs[0]); for(i =0; i < G.n; ++i) pre[i] = i; printf("最小生成树之kruskal算法路径:\n"); kruskal(G, pre); return 0; } void create(MGraph &G) { int i, j; printf("请输入顶点数和边数:\n"); scanf("%d %d", &G.n, &G.e); printf("请输入顶点编号:\n"); for(i = 0; i < G.n; ++i) scanf("%d", &G.vexs[i]); printf("顶点编号分别为:"); for(i = 0; i < G.n; ++i) printf("%d ", G.vexs[i]); printf("\n请输入邻接矩阵:\n"); //两个非连接点之间距离此处用9表示 for(i = 0; i < G.n; ++i) for(j = 0; j < G.n; ++j) { printf("arcs[%d][%d] = ", i, j); scanf("%d", &G.arcs[i][j]); } printf("该图的邻接矩阵:\n"); for(i = 0; i < G.n; ++i) { for(j = 0; j < G.n; ++j) printf("%d ", G.arcs[i][j]); printf("\n"); } } //prim算法 void prim(MGraph G, int u) { int i, j, t, a, b, k = 1; int min, low[10]; for(i = 0; i < G.n; ++i) visit[i] = false; visit[0] = true; low[0] = 0; min = 99; for(t = 1; t < G.n; ++t) { min = 99; for(i = 0; (i < k) && (i < G.n); ++i) { for(j = 0; j < G.n; ++j) if((min > G.arcs[low[i]][j]) && (low[i] != j) && (!visit[j])) { min = G.arcs[low[i]][j]; a = low[i]; b = j; } } visit[b] = true; low[k++] = b; printf("(%d, %d) = %d\n", a, b, min); } } //并查集算法 int find(int x, int *pre) { int r = x; while(pre[r] != r) r = pre[r]; return r; } bool join(int x, int y, int *pre) { int fx = find(x, pre); int fy = find(y, pre); if(fx != fy) return true; else return false; } //kruskal算法 void kruskal(MGraph G, int *pre) { int i, j, k, a, b, min; for(k = 1; k < G.n; ++k) { min = 99; for(i = 0; i < G.n; ++i) { for(j = 0; j < G.n; ++j) if((min > G.arcs[i][j]) && (i != j) && join(i, j, pre)) { min = G.arcs[i][j]; a = i; b = j; } } printf("(%d, %d) = %d\n", a, b, min); a = find(a, pre); b = find(b, pre); if(a < b) pre[a] = b; else pre[b] = a; } }
示例:(读者可自行验证)
时间: 2024-10-09 06:59:11