生成树:
所有顶点均由边连接在一起,但不存在回路的图
一个图可以有多颗不同的生成树
含有n个顶点n-1条边的图不一定是生成树
所有生成树具有以下特点:
1.生成树的顶点个数与图的顶点个数相同
2.生成树是图的极小连通子图,去掉一条边则非连通
3.一个有n个顶点的连通图的生成树有n-1条边
4.在生成树中再加一条边必然形成回路
5.生成树中任意两个顶点间的路径是为宜的
生成树有很多种算法实现,比如常用的深度优先搜索(DFS)和广度优先搜索(BFS)等。
最小生成树:
给定一个无相网络,在该网的所有生成树中,使得各边权值之和最小的那颗生成树成为该网的最小生成树,也叫最小代价树。
MST性质:设N=(V,E)是一个;联通网,U是顶点集V的一个非空子集。若边(u,v)是一条具有最小权值的边,其中u属于U,v属于V-U,则必然存在一颗包含(u,v)的最小生成树。
在构造生成树中,图中n个顶点分属两个集合:
1.已落到生成树上的顶点集:U
2.尚未落到生成树上的顶点集:V-U
然后就在U中顶点和V-U中顶点的边中选权值最小的边。
普里姆算法:
#include "stdio.h"
#include "stdlib.h"
#include "limits.h"
int n;
void prim(int graph[n][n]);
int min_d(int key [], int mark []);
int main()
{
scanf("%d",&n); //输入邻接矩阵的大小
int graph[n][n];
for(int i = 0 ; i < n ; i++)
for(int j = 0 ; j < n ; j++)
scanf("%d",graph[i]+j);
prim(graph);
}
//返回未标记顶点中距离离根最近的下标
int min_d(int key [], int mark [])
{
int min=INT_MAX,xiabiao;
for(int i = 0 ; i < n; i++)
if(mark[i] == 0 && key[i] < min)
min = key[i] , xiabiao = i;
return xiabiao;
}
//普里姆生成最小树
void prim(int graph[n][n])
{
int parent[n];//最小生成树中每个顶点的父节点
int key[n]; //存贮每个顶点与当前最小生成树之间的最短边权值
int mark[n]; //每个顶点是否包含在最小生成树中
for(int i = 0 ; i < n ; i++)
key[i]=INT_MAX,mark[i]=0;
key[0]=0;
for(int count = 0 ; count < n-1; count++)
{
int u = min_d(key , mark);
mark[u] = 1;
for (int v = 0; v < n; v++)
if (graph[u][v] && mark[v] == 0 && graph[u][v] < key[v])
parent[v] = u, key[v] = graph[u][v];
}
// 打印生成的最小生成树
void printMST(int parent[], int graph[n][n])
{
printf("Edge \tWeight\n");
for (int i = 1; i < n; i++)
printf("%d - %d \t%d \n", parent[i], i, graph[i][parent[i]]);
}
}