【最小生成树】Prim 普里姆算法,Kruskal 克鲁斯卡尔算法生成 最小生成树

版权声明:谢谢 https://blog.csdn.net/Waybyway/article/details/84872577

1.Analyse

来自两位科学家。

生成最小生成树,从0顶点出发,最小生成树包含所以顶点>_<,这个作业难道好像就是似乎改个矩阵?

最好还是把最小生成树变成一条路线,这样就不用去,自己找路线了。

题目图如图


2.源自老师的Code Print

1Prim

#include <stdio.h>
#define MAXV 20			//最多顶点数
#define INF 32767       //INF表示∞
typedef char InfoType;
typedef struct
{
	int no;						//顶点编号
	InfoType info;				//顶点其他信息
} VertexType;					//顶点类型
typedef struct  				//图的定义
{
	int edges[MAXV][MAXV]; 		//邻接矩阵
   	int n,e;   					//顶点数,弧数
	VertexType vexs[MAXV];		//存放顶点信息
} MGraph;						//图的邻接矩阵类型

void Prim(MGraph g,int v)
{
	int lowcost[MAXV];			//顶点i是否在U中
	int min;
	int closest[MAXV],i,j,k;
	for (i=0;i<g.n;i++)          	//给lowcost[]和closest[]置初值
	{
		lowcost[i]=g.edges[v][i];
		closest[i]=v;
	}
	for (i=1;i<g.n;i++)          	//找出n-1个顶点
	{
		min=INF;
		for (j=0;j<g.n;j++)       //在(V-U)中找出离U最近的顶点k
			if (lowcost[j]!=0 && lowcost[j]<min)
			{
				min=lowcost[j];
				k=j;			//k记录最近顶点的编号
			}
		printf(" 边(%d,%d)权为:%d\n",closest[k],k,min);
		lowcost[k]=0;         	//标记k已经加入U
		for (j=0;j<g.n;j++)   	//修改数组lowcost和closest
			if (g.edges[k][j]!=0 && g.edges[k][j]<lowcost[j])
			{
				lowcost[j]=g.edges[k][j];
				closest[j]=k;
			}
	}
}
int main()
{
	int i,j;
	MGraph g;
	g.n=6;g.e=20;
	int a[6][MAXV]={
		{0  ,5  ,8  ,7  ,INF,3  },
		{5  ,0  ,4  ,INF,INF,INF},
		{8  ,4  ,0  ,5  ,INF,9  },
		{7  ,INF,5  ,0  ,5  ,6  },
		{INF,INF,INF,5  ,0  ,1  },
		{3  ,INF,9  ,6  ,1  ,0  }};
	for (i=0;i<g.n;i++)
		for (j=0;j<g.n;j++)
			g.edges[i][j]=a[i][j];
	printf("最小生成树构成:\n");
	Prim(g,0);
	printf("\n");
    return 0;
}

2.Kruskal

#include <stdio.h>
#define MaxSize 100
#define INF 32767	//INF表示∞
#define	MAXV 100	//最大顶点个数
typedef int InfoType;

typedef struct
{
	int no;						//顶点编号
	InfoType info;				//顶点其他信息
} VertexType;					//顶点类型
typedef struct  				//图的定义
{
	int edges[MAXV][MAXV]; 		//邻接矩阵
   	int n,e;   					//顶点数,弧数
	VertexType vexs[MAXV];		//存放顶点信息
} MGraph;						//图的邻接矩阵类型

typedef struct
{
	int u;			//边的起始顶点
    int v;			//边的终止顶点
    int w;			//边的权值
} Edge;

void InsertSort(Edge E[],int n) //对E[0..n-1]按递增有序进行直接插入排序
{
	int i,j;
	Edge temp;
	for (i=1;i<n;i++)
	{
		temp=E[i];
		j=i-1;				//从右向左在有序区E[0..i-1]中找E[i]的插入位置
		while (j>=0 && temp.w<E[j].w)
		{
			E[j+1]=E[j];	//将关键字大于E[i].w的记录后移
			j--;
		}
		E[j+1]=temp;		//在j+1处插入E[i]
	}
}
void Kruskal(MGraph g)
{
	int i,j,u1,v1,sn1,sn2,k;
	int vset[MAXV];
	Edge E[MaxSize];				//存放所有边
	k=0;							//E数组的下标从0开始计
	for (i=0;i<g.n;i++)				//由g产生的边集E
		for (j=0;j<g.n;j++)
			if (g.edges[i][j]!=0 && g.edges[i][j]!=INF)
			{
				E[k].u=i;E[k].v=j;E[k].w=g.edges[i][j];
				k++;
			}
	InsertSort(E,g.e);				//采用直接插入排序对E数组按权值递增排序

	for (i=0;i<g.n;i++) 			//初始化辅助数组
		vset[i]=i;
	k=1;                 			//k表示当前构造生成树的第几条边,初值为1
	j=0;                 			//E中边的下标,初值为0
	while (k<g.n)       			//生成的边数小于n时循环
	{
		u1=E[j].u;v1=E[j].v;        //取一条边的头尾顶点
		sn1=vset[u1];
		sn2=vset[v1]; 				//分别得到两个顶点所属的集合编号
		if (sn1!=sn2)     	  		//两顶点属于不同的集合,该边是最小生成树的一条边
		{
			printf("  (%d,%d):%d\n",u1,v1,E[j].w);
			k++;                    //生成边数增1
			for (i=0;i<g.n;i++)     //两个集合统一编号
				if (vset[i]==sn2)  	//集合编号为sn2的改为sn1
				    vset[i]=sn1;
		}
		j++;   						//扫描下一条边
	}
}
int main()
{
	int i,j;
	MGraph g;
	g.n=6;g.e=20;
	int a[6][MAXV]={
		{0  ,5  ,8  ,7  ,INF,3  },
		{5  ,0  ,4  ,INF,INF,INF},
		{8  ,4  ,0  ,5  ,INF,9  },
		{7  ,INF,5  ,0  ,5  ,6  },
		{INF,INF,INF,5  ,0  ,1  },
		{3  ,INF,9  ,6  ,1  ,0  }};
	for (i=0;i<g.n;i++)
		for (j=0;j<g.n;j++)
			g.edges[i][j]=a[i][j];
	printf("最小生成树构成:\n");
	Kruskal(g);
	printf("\n");
    return 0;
}

3.End

?_?,没有其他东西?

猜你喜欢

转载自blog.csdn.net/Waybyway/article/details/84872577