一个连通图的生成树是图的极小连通子图。它包含图中的所有顶点,并且只含尽可能少的边。若砍去它的一条边,就会使生成树变成非连通图;若给它增加一条边,则会形成一条回路。
最小生成树有如下性质:
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;
}
}
示例:(读者可自行验证)