1.最小生成树的概念
最小生成树 由一个网络生成的各边的权数总和最小的生成树,记为MST(Minimum Cost Spanning Tree)。
MST性质 设N=(V,{E})是一个连通的网络,U是V的真子集,若边(u,v)[uÎU,vÎV-U]是E中所有一个端点在U内,一个端点不在U内的边中权值最小的一条边(轻边),则一定存在G的一棵生成树包括此边。
1.Prim算法:
当前关联vi的轻边权值
该边依附的U集合中的顶点下标
示例初值: 0 1 2 3 4 5
lowcost 0 6 1 5 µ µ
adjvex 0 0 0 0 0 0
算法步骤
1)初始化closedge[j](j=0..n-1) O(n)
2)重复n-1次以下操作:
2.1)在closedge[j](j=0..n-1)中选择最小且非0的 lowcost,记录其j 值(设为k)和相应的adjvex; O(n2)
2.2)输出该边(adjvex,k); O(n)
2.3)顶点k并入U集:closedge[k].lowcost=0; O(n)
2.4)调整候选边集closedge[j](j=0..n-1): O(n2)
若G.arcs[k][j]< closedge[j].lowcost,
则更改closedge[j]:adjvex=k,lowcost=G.arcs[k][j]
O(n2)
C++代码
#include<iostream>
#include<stdlib.h>
using namespace std;
#define MAX 100
class block {
public:
int lowcost;
int adjvex; //关联的顶点
};
class Graph {
public:
char vertex_num[MAX]; //顶点信息对应的矩阵的编号
int e[MAX][MAX];
int vexnum; //图的顶点数目
int edgenum; //图的边的数目
};
void Prim(Graph G);
int findmin(block*, int);
int main()
{
int i, j;
//正确输入用关联矩阵来存储一个图,并且定义closeedge
Graph G;
cout<< "请输入无向图的顶点数目和图的边的数目\n";
cin >> G.vexnum;
cin >> G.edgenum;
//初始化关联矩阵
for(i=1;i<=G.vexnum;i++)
for (j = 1; j <= G.vexnum; j++)
{
if (i == j)
G.e[i][j] = 0;
else
G.e[i][j] = 99999;
}
cout << "请输入各顶点的信息\n";
for (i = 1; i <= G.vexnum; i++)
{
cin >> G.vertex_num[i];
}
cout << "请输入各边的相关信息\n";
int j1,j2;
char vert1, vert2;
int weight;
for (i = 1; i <= G.edgenum; i++)
{
cin >> vert1;
cin >> vert2;
cin >> weight;
for (j1 = 1; G.vertex_num[j1] != vert1; j1++);
for (j2 = 1; G.vertex_num[j2] != vert2; j2++);
G.e[j1][j2] = weight;
G.e[j2][j1] = weight;
}
/*//存储检查
for (i = 1; i <= G.vexnum; i++)
{
for (j = 1; j <= G.vexnum; j++)
cout << G.e[i][j] << " ";
cout << "\n";
}*/
Prim(G);
system("pause");
}
void Prim(Graph G)
{
block closeedge[MAX];
//先初始化closeedge数组,用e[][]的某一行(我选的是第一行)进行初始化
//然后选取第一行中的最小权值连接的顶点,输出信息,加入到U集合中,(即将lowcost=0)
//并且用该顶点去疏散其他还未进入U集合的点,如此往复
int i, k, j;
for (i = 1; i <= G.vexnum; i++)
{
closeedge[i].adjvex = 1;
closeedge[i].lowcost = G.e[1][i];
}
cout << "从1号顶点开始\n";
for (i = 2; i <= G.vexnum; i++)
{
k = findmin(closeedge,G.vexnum);
closeedge[k].lowcost = 0; //加入U集合
cout << "下一个顶点是" << G.vertex_num[k]<<" ";
cout<<"对应的边的权值是" << G.e[k][closeedge[k].adjvex]<<"\n";
for (j = 1; j <= G.vexnum; j++)
{
if (G.e[k][j] < closeedge[j].lowcost)
{
closeedge[j].lowcost = G.e[k][j];
closeedge[j].adjvex = k;
}
}
}
}
int findmin(block*close,int vexnum)
{
int min = 1, lows = 99999;
int i;
for (i = 1; i <= vexnum; i++)
{
if (close[i].lowcost < lows&&close[i].lowcost != 0)
{
lows = close[i].lowcost;
min = i;
}
}
return min;
}
2.Kruskal算法
1)初始化T:顶点集=所有顶点,每个独立的顶点作为一棵树,边集=ø; O(n)
2)依权值递增序对图G的边排序,结果为E[0..e-1] O(elge)
3)依次检测E中的各边(u,v): O(elge)
3.1) 若u和v分属于T中两棵不同的树,则将该边加入T,并合并u和v分属的两棵树
3.2) 若T中所有顶点尚未属于一棵树,转3)