最小生成树的两种算法
1.普利姆算法(Prim)
输入输出样例
6 10
1 2 3 4 5 6
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6
1->3:1
3->6:4
6->4:2
3->2:5
2->5:3
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#define max 20
typedef struct node
{
int weiget;//权值
int ver;//顶点数据
}node;
typedef struct Vertex
{
int vernum, srcnum;
int arc[max][max];
node vertex[max];
}Vertex;
void CreateGraph(Vertex* G)
{
scanf("%d %d", &G->vernum, &G->srcnum);
for (int i = 1; i <= G->vernum; i++)
{
scanf("%d", &G->vertex[i].ver);
}
for (int i = 1; i <= G->vernum; i++)
{
for (int j = 1; j <= G->vernum; j++)
{
if (i == j)
{
G->arc[i][j] = 0;
}
else
{
G->arc[i][j] = 65535;
}
}
}
for (int i = 1; i <= G->srcnum; i++)
{
int v1, v2;
scanf("%d %d %d", &v1, &v2, &G->vertex[i].weiget);
G->arc[v1][v2] = G->vertex[i].weiget;
G->arc[v2][v1] = G->arc[v1][v2];
}
}
void Prim_min_tree(Vertex G)
{
int lowcost[max];//存储最小权值
int jver[max];//保存相关顶点下标
lowcost[1] = 0;
jver[1] = 1;
for (int i = 2; i <= G.vernum; i++)
{
lowcost[i] = G.arc[1][i];
jver[i] = 1;
}
for (int i = 2; i <= G.vernum; i++)
{
int min = 65535;
int p = 2, q = 0;
while (p <= G.vernum)
{
if (lowcost[p] != 0 && lowcost[p] < min)
{
min = lowcost[p];
q = p;
}
p++;
}
printf("%d->%d:%d\n", jver[q], q, G.arc[jver[q]][q]);
lowcost[q] = 0;
for (int j = 2; j <= G.vernum; j++)
{
if (lowcost[j] != 0 && G.arc[q][j] < lowcost[j])
{
lowcost[j] = G.arc[q][j];//将权值较小的边并入lowcost
jver[j] = q;
}
}
}
}
int main()
{
Vertex G;
CreateGraph(&G);
Prim_min_tree(G);
return 0;
}
2.克鲁斯卡尔算法(Kruskal)
将各边按照权值从小到大排序:
begin 1 4 2 3 1 2 3 1 3 5
end 3 6 5 6 4 3 4 2 5 6
weight 1 2 3 4 5 5 5 6 6 6
输入输出样例:
6 10
1 2 3 4 5 6
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6
1->3:1
4->6:2
2->5:3
3->6:4
2->3:5
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#define max 20//输入的最大的顶点个数
typedef struct node
{
int weiget;//权值
int ver;//顶点数据
}node;
typedef struct Vertex
{
int vernum, srcnum;
int arc[max][max];
node vertex[max];
}Vertex;
typedef struct Edge//边集结构体
{
int begin;
int end;
int weight;
}Edge;
//构造边集结构体数组
Edge edge[max * (max - 1)];//有max个顶点的强连通图最多有max*(max-1)条边
void CreateGraph(Vertex* G)
{
scanf("%d %d", &G->vernum, &G->srcnum);
for (int i = 1; i <= G->vernum; i++)
{
scanf("%d", &G->vertex[i].ver);
}
for (int i = 1; i <= G->vernum; i++)
{
for (int j = 1; j <= G->vernum; j++)
{
G->arc[i][j] = 0;
}
}
for (int i = 1; i <= G->srcnum; i++)
{
int v1, v2;
scanf("%d %d %d", &v1, &v2, &G->vertex[i].weiget);
G->arc[v1][v2] = G->vertex[i].weiget;
G->arc[v2][v1] = G->arc[v1][v2];
}
}
void Sort_Edges(Vertex G)//将邻接矩阵G转化为边集数组,之后边集数组从小到大排序
{
int k = 1;
for (int i = 1; i <= G.vernum; i++)
{
for (int j = i; j <= G.vernum; j++)//这时我们只需要二阶矩阵的上三角矩阵就行了
{
if (G.arc[i][j] != 0)
{
edge[k].begin = i;
edge[k].end = j;
edge[k].weight = G.arc[i][j];
k++;
}
}
}
Edge temp;
for (int i = 1; i < k; i++)
{
for (int j = 1; j < k - i; j++)//按权值从小到大对结构体数组edge排序
{
if (edge[j].weight > edge[j + 1].weight)
{
temp = edge[j];
edge[j] = edge[j + 1];
edge[j + 1] = temp;
}
}
}
}
//查找与elem顶点连线的顶点下标
int find(int* jver, int elem)
{
while (jver[elem] > 0)
{
elem = jver[elem];
}
return elem;
}
void Kruskal_min_tree(Vertex G)
{
int jver[max] = { 0 };
Sort_Edges(G);
for (int i = 1; i <= G.srcnum; i++)
{
int n = find(jver, edge[i].begin);
int m = find(jver, edge[i].end);
if (n != m)
{
jver[n] = m;
printf("%d->%d:%d\n", edge[i].begin, edge[i].end, edge[i].weight);
}
}
}
int main()
{
Vertex G;
CreateGraph(&G);
Kruskal_min_tree(G);
return 0;
}