最小生成树解决的是找出图的最小连通路径,其具有MST性质:假设图G=(V,E)为一个无向连通图,U是顶点集V的一个非空子集,而u∈U,v∈V-U。若(u,v)为一条两个集合间具有最小权值的边,则必存在一颗包含(u,v)的最小生成树。Prime算法和Kruskal算法皆利用此性质得到最小生成树。
/*Prime算法
初始化:G=(V,E),U={v0},TE={ };
重复下列操作直到U=V
1.在E中寻找最短边(u,v),满足u∈U,v∈V-U;
2.U=U+{v};
3.TE=TE+{(u,v)};*/
int groph[MAX][MAX];
struct se
{
int lowcost;
int adjvex;
};
int minedge(vector<se>& shortedge, int n)//在shortedge中查找最小权值
{
int t = INF, k = 0;
int i = 0;
for (vector<se>::iterator it = shortedge.begin(); it != shortedge.end(); ++it,++i)
{
if (it->lowcost > 0 && it->lowcost < t)
{
t = it->lowcost;
k = i;
}
}
return k;
}
int prime(int n)
{
int sum = 0;
vector<se> shortedge;//存储已连接点集和未连接点集之间最短点集
for (int i = 0; i < n; ++i)//初始化shortedge
{
se t;
t.adjvex = 0;
t.lowcost = groph[0][i];
shortedge.push_back(t);
}
for (int i = 1; i < n; ++i)
{
int k = minedge(shortedge,n);//寻找最短边的邻接点
cout << "(" << k << "," << shortedge[k].adjvex << ")" << shortedge[k].lowcost << endl;
sum += shortedge[k].lowcost;
shortedge[k].lowcost = 0;
/*更新最短边集*/
for (int j = 1; j < n; ++j)
{
if (groph[k][j] < shortedge[j].lowcost)
{
shortedge[j].adjvex = k;
shortedge[j].lowcost = groph[k][j];
}
}
}
return sum;
}
/*Kruskal算法:G的最小生成树T,按权值从小到大依次考察边集E中边的顶点是否在一个连通分量里。
若在两个不同的连通分量里就将此边加入TE,并将两个连通分量连为一个,直到T中只有一个连通分量
初始化:G=(V,E),T=(U,TE),U=V,TE={ };
重复下列操作直到T中连通分量个数为1
1.找E中最短边(u,v);
2.若u,v位于两个不同的连通分量:
将边(u,v)并入TE;
将这两个连通分量合并;
3.在E中标记(u,v)不参与后续最短边选取*/
int groph[MAX][MAX];
struct et
{
int from, to;
int length;
};
list<et> Egroph;
int findroot(int parent[],int v)//查询该点父节点用于检查是否在一个连通分量上
{
int t = v;
while (parent[t] > -1)
t=parent[t];
return t;
}
int kruskal(int n)
{
int *parent=new int[n];
int sum = 0,num=0;
for (int i = 0; i < n; ++i)
{
parent[i] = -1;
}
for ( list<et>::iterator i = Egroph.begin(); i !=Egroph.end(); ++i)
{
//判断两个顶点是否位于相同的连通分量
int vex1 = findroot(parent, i->from);
int vex2 = findroot(parent, i->to);
if (vex1 != vex2)
{
cout << "(" << i->from << "," << i->to << ")" << endl;
sum += i->length;
parent[vex2] = vex1;
num++;
if (num == n - 1)
return sum;
}
}
}