最小生成树Prim算法C语言-图解

最小生成树Prim算法

算法简介

普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小。

图解

1、原始的加权连通图。每条边一侧的数字代表其权值。

请添加图片描述

2、顶点 D D D被任意选为起始点。顶点 A 、 B 、 E A、B、E ABE F F F通过单条边与 D D D相连。 A A A是距离 D D D最近的顶点,因此将 A A A 及对应边 A D AD AD以高亮表示。

请添加图片描述

3、下一个顶点为距离 D 或 A D或A DA最近的顶点。 B 距 D 为 9 , 距 A 为 7 , E 为 15 , F 为 6 B距D为9,距A为7,E为15,F为6 BD9A7E15F6。因此, F 距 D 或 A F距D或A FDA最近,因此将顶点 F 与 相 应 边 D F F与相应边DF FDF以高亮表示。

请添加图片描述

4、 算 法 继 续 重 复 上 面 的 步 骤 。 距 离 A 为 7 的 顶 点 B 被 高 亮 表 示 算法继续重复上面的步骤。距离A为7的顶点B被高亮表示 A7B

请添加图片描述

5、在当前情况下,可以在 C 、 E 与 G C、E与G CEG间进行选择。 C 距 B 为 8 , E 距 B 为 7 , G 距 F 为 11 C距B为8,E距B为7,G距F为11 CB8EB7GF11。点 E E E最近,因此将顶点 E E E与相应边 B E BE BE高亮表示。

请添加图片描述

6、这里,可供选择的顶点只有 C 和 G 。 C 距 E 为 5 , G 距 E 为 9 , 故 选 取 C , 并 与 边 E C C和G。C距E为5,G距E为9,故选取C,并与边EC CGCE5GE9CEC一同高亮表示。

请添加图片描述
7、顶点 G G G是唯一剩下的顶点,它距 F F F 11 11 11 距 E 为 9 , E 最 近 , 故 高 亮 表 示 G 及 相 应 边 E G 距E为9,E最近,故高亮表示G及相应边EG E9EGEG

请添加图片描述

8、所有顶点均已被选取,图中绿色部分即为连通图的最小生成树。在此例中,最小生成树的权值之和为 39 39 39

请添加图片描述

代码分析

把图存入 G r a p h [ N ] [ N ] Graph[N][N] Graph[N][N]

	int Graph[N][N]={
    
    
		{
    
    M, M, M, M, M, M, M},
		{
    
    M, 0, 6, 1, 5, M, M},
        {
    
    M, 6, 0, 5, 3, M, M},
        {
    
    M, 1, 5, 0, 5, 6, 4},
        {
    
    M, 5, 3, 5, 0, M, 2},
        {
    
    M, M, M, 6, M, 0, 6},
        {
    
    M, M, M, 4, 2, 6, 0},
    };

调用 P r i m Prim Prim方法

int prim(int graph[][N])
{
    
    
	int n = 6;
	int lowcost[M];//记录边对应的权值 
	int mst[M];//记录权值对应的边  起点是值  终点是下标 
	int i, j, min, minid, sum = 0;
	for (i = 2; i <= n; i++)
	{
    
    
		lowcost[i] = graph[1][i];
		mst[i] = 1;
	}
	mst[1] = 0;
	for (i = 2; i <= n; i++)
	{
    
    
		min = M;
		minid = 0;
		for (j = 2; j <= n; j++)
		{
    
    
			if (lowcost[j] < min && lowcost[j] != 0)
			{
    
    
				min = lowcost[j];
				minid = j;
			}
		}
		cout << "V" << mst[minid] << "-V" << minid << "=" << min << endl;
		sum += min;
		lowcost[minid] = 0;
		for (j = 2; j <= n; j++)
		{
    
    
			if (graph[minid][j] < lowcost[j])
			{
    
    
				lowcost[j] = graph[minid][j];
				mst[j] = minid;
			}
		}
	}
	return sum;
}

P r i m Prim Prim方法中第一个 f o r for for循环把第一个点对应的边(权值)放入 l o w c o s t [ i ] lowcost[i] lowcost[i]数组中
m s t [ ] mst[] mst[]数组,其下标记录终点,下标对应的值是起点。这样就记录了一条边

主要做一个初始化的工作

	int lowcost[M];//记录边对应的权值 
	int mst[M];//记录权值对应的边  起点是值  终点是下标 
	int i, j, min, minid, sum = 0;
	for (i = 2; i <= n; i++)
	{
    
    
		lowcost[i] = graph[1][i];
		mst[i] = 1;
	}
	mst[1] = 0;

第二个 f o r for for循环,每一次都能找到一条最小的边

	for (i = 2; i <= n; i++)
	{
    
    
		min = M;
		minid = 0;
		for (j = 2; j <= n; j++)
		{
    
    
			if (lowcost[j] < min && lowcost[j] != 0)
			{
    
    
				min = lowcost[j];
				minid = j;
			}
		}
		cout << "V" << mst[minid] << "-V" << minid << "=" << min << endl;
		sum += min;
		lowcost[minid] = 0;
		for (j = 2; j <= n; j++)
		{
    
    
			if (graph[minid][j] < lowcost[j])
			{
    
    
				lowcost[j] = graph[minid][j];
				mst[j] = minid;
			}
		}
	}

第二个 f o r for for循环中的第一个 f o r for for循环会找到当前边集中权值最小的,并且记录其权值和下标.

		min = M;
		minid = 0;
		for (j = 2; j <= n; j++)
		{
    
    
			if (lowcost[j] < min && lowcost[j] != 0)
			{
    
    
				min = lowcost[j];
				minid = j;
			}
		}
		cout << "V" << mst[minid] << "-V" << minid << "=" << min << endl;
		sum += min;
		lowcost[minid] = 0;

第二个 f o r for for循环中的第二个 f o r for for循环会找到当前新加入的边中权值比已经存入的更小的,并且记录其权值和下标.

		for (j = 2; j <= n; j++)
		{
    
    
			if (graph[minid][j] < lowcost[j])
			{
    
    
				lowcost[j] = graph[minid][j];
				mst[j] = minid;
			}
		}

代码

#include<iostream>
using  namespace std;

#define M 65535 //无穷大 
#define N 8  //顶点数 

int prim(int graph[][N])
{
    
    
	int n = 6;
	int lowcost[M];//记录边对应的权值 
	int mst[M];//记录权值对应的边  起点是值  终点是下标 
	int i, j, min, minid, sum = 0;
	for (i = 2; i <= n; i++)
	{
    
    
		lowcost[i] = graph[1][i];
		mst[i] = 1;
	}
	mst[1] = 0;
	for (i = 2; i <= n; i++)
	{
    
    
		min = M;
		minid = 0;
		for (j = 2; j <= n; j++)
		{
    
    
			if (lowcost[j] < min && lowcost[j] != 0)
			{
    
    
				min = lowcost[j];
				minid = j;
			}
		}
		cout << "V" << mst[minid] << "-V" << minid << "=" << min << endl;
		sum += min;
		lowcost[minid] = 0;
		for (j = 2; j <= n; j++)
		{
    
    
			if (graph[minid][j] < lowcost[j])
			{
    
    
				lowcost[j] = graph[minid][j];
				mst[j] = minid;
			}
		}
	}
	return sum;
}
 
int main()
{
    
    
	int cost;
	int Graph[N][N]={
    
    
		{
    
    M, M, M, M, M, M, M},
		{
    
    M, 0, 6, 1, 5, M, M},
        {
    
    M, 6, 0, 5, 3, M, M},
        {
    
    M, 1, 5, 0, 5, 6, 4},
        {
    
    M, 5, 3, 5, 0, M, 2},
        {
    
    M, M, M, 6, M, 0, 6},
        {
    
    M, M, M, 4, 2, 6, 0},
    };
	//求解最小生成树 
	cost = prim(Graph);
	//输出最小权值和 
	cout << "最小权值和=" << cost << endl;
	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Lazy_Goat/article/details/120537907