最小生成树(带权无向图)

在一个无向图中找出一棵最小生成树:ios

      一个无向图G的最小生成树就是由该图的那些链接G的全部顶点的边构成的树,且其总价值最低,最小生成树存在当且仅当G是连通的。在最小生成树中边的条数是|V|-1,而且无圈。算法

      对于任一个生成树T,若是将一条不属于T的边e添加进来,则产生一个圈。若是从该圈中除去任意一条边,则又恢复生成树的特性。若是边e的值比除去的边的值低,那么新的生成树的值就比原生成树的值低。若是在创建生成树时添加的边在全部避免成圈的边中值最小,那么最后获得的生成树的值不能再改进,由于任意一条替代的边的值都大于等于已存在于该生成树中的一条边的值,它指出,对于最小生成树这种贪欲是成立的。下图是图G与它的最小生成树。数组


利用Prim算法计算最小生成树:spa

        计算最小生成树的一种方法是使其连续的一步步长成。在每一步,都要把一个节点当作根并往上加边,这样也就把相关联的顶点加到增加的树上。code

       在算法的任意时刻,咱们均可以看到一个已经添加到树上的顶点集,而其他顶点还没有加到这棵树上。此时,算法在每一阶段均可以经过选择边(u,v),使得(u,v)的值是全部u在树上但v不在树上的值中的最小者,而找出一个新的顶点并把它添加到这棵树中。下图指出该算法如何从v1开始构建最小生成树。开始时,v1在构建中的树上,它作为树的根可是没有边。每一步添加一条边和一个顶点到树上。blog


由此可得出生成树的边为:(v2,v1)、(v3,v4)、(v4,v1)、(v5,v7)、(v6,v7)、(v7,v4),生成树总的价值是16。递归

程序以下:string

#include<iostream>
#include<assert.h>
#include<string>
#include<limits.h>

#define NUM 7
using namespace std;

//利用二维数组建立有向图的邻接矩阵
void CreateMatrix(int mat[NUM][NUM]);
//利用Prim算法求解最小生成树
void DijkstraSearch(int mat[NUM][NUM], int i, int visit[NUM], int dist[NUM], int path[NUM]);

int main()
{
	//建立有向图的带有权值的邻接矩阵
	int mat[NUM][NUM];
	for (int i = 0; i < NUM;i++)
	{
		for (int j = 0; j < NUM;j++)
		{
			mat[i][j] = INT_MAX;
		}
	}
	CreateMatrix(mat);
	int visit[NUM] = {0};
	int dist[NUM];
	for (int i = 0; i < NUM;i++)
	{
		dist[i] = INT_MAX;
	}
	int path[NUM] = {0};
	
	//利用Prim算法求解最小生成树
	//初始源点的dist初始化为0,path初始化为0
	dist[0] = 0;
	path[0] = 0;
	DijkstraSearch(mat,0,visit,dist,path);

	//输出最小生成树的边及相应权值,总权值
	int totalValue = 0;
	for (int i = 1; i < NUM;i++)
	{
		totalValue += dist[i];
		printf("最小生成树的边:<v%d , v%d>",(i+1),(path[i]+1));
		printf(" 权值:%d",dist[i]);
		printf("\n");
	}
	printf("最小生成树的总权值:%d",totalValue);
	printf("\n");

	return 0;
}


//利用二维数组建立有向图的邻接矩阵,带权值
void CreateMatrix(int mat[NUM][NUM])
{
	mat[0][1] = 2;
	mat[0][2] = 4;
	mat[0][3] = 1;

	mat[1][0] = 2;
	mat[1][3] = 3;
	mat[1][4] = 10;

	mat[2][0] = 4;
	mat[2][3] = 2;
	mat[2][5] = 5;

	mat[3][0] = 1;
	mat[3][1] = 3;
	mat[3][2] = 2;
	mat[3][4] = 7;
	mat[3][5] = 8;
	mat[3][6] = 4;

	mat[4][1] = 10;
	mat[4][3] = 7;
	mat[4][6] = 6;

	mat[5][2] = 5;
	mat[5][3] = 8;
	mat[5][6] = 1;

	mat[6][3] = 4;
	mat[6][4] = 6;
	mat[6][5] = 1;
}

//利用Prim算法求解最小生成树
void DijkstraSearch(int mat[NUM][NUM], int i, int visit[NUM], int dist[NUM], int path[NUM])
{
	//初始化
	visit[i] = 1;
	//dist[i] = 0;
	//path[i]=0;

	//访问与顶点i相邻接的未被访问的顶点,获取路径长度,若是小于以前路径长度则替换,并记录路径
	for (int j = 0; j < NUM;j++)
	{
		if (visit[j] == 0 && mat[i][j] != INT_MAX)
		{
			if (mat[i][j]<dist[j])
			{
				dist[j] = mat[i][j];
				path[j] = i;
			}
		}
	}

	//在未被访问过的顶点中寻找路径最短的顶点
	int minDist = -1;
	for (int m = 0;m<NUM;m++)
	{
		if (visit[m] == 0)
		{
			minDist = m;
			break;
		}
	}
	for (int k = minDist + 1; k<NUM; k++)
	{
		if (visit[k] == 0 && dist[k]<dist[minDist])
		{
			minDist = k;
		}
		
	}
	//若是找到继续寻找到下一个顶点的最短路径(递归)
	if (minDist != -1)
	{
		DijkstraSearch(mat, minDist, visit, dist, path);
	}
}

结果以下:it