1. 程式人生 > >【最小生成樹】Prim 普里姆演算法,Kruskal 克魯斯卡爾演算法生成 最小生成樹

【最小生成樹】Prim 普里姆演算法,Kruskal 克魯斯卡爾演算法生成 最小生成樹

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

?_?,沒有其他東西?