最小生成树问题
什么是最小生成树
- 是一棵树
- 是生成树
- 边的权重和最小
- 向生成树中任加一条边,都一定构成回路
贪心算法
- 什么是“贪”:每一步都要最好的
- 什么是“好”:权重最小的边
- 需要约束:
- 只能用图里有的边
- 只能正好用掉|V|-1条边
- 不能有回路
Prim算法—让一棵小树长大
void Prim()
{
MST = {s};
while (1) {
V = 未收录顶点中dist最小者;
if( 这样的V不存在 )
break;
将V收录进MST:dist[V] = 0;
for( V 的每个邻接点 W )
if (dist[W]!=0)
if( E(V,W) < dist[W] ) {
dist[W] = E(V,W);
parent[W] = V;
}
}
if( MST中收到的顶点不到|V|个 )
Error ("生成树不存在");
}
Kruskal算法—将森林合并成树
void Kruskal ( Graph G )
{
MST = { };
while ( MST中不到|V|-1条边 && E中还有边 ) {
从E中取一条权重最小的边E(v,w);
将E(v,w)从E中删除;
if( E(v,w)不在MST中构成回路)
将E(v,w)加入MST;
else
彻底无视E(v,w);
}
if( MST中找不到|V|-1条边 )
Error ("生成树不存在");
}
- 如果图中所有边的权值都不同,只有一种最小生成树
- 但是如果有2条或以上的边有相同权值,这个最小生成树就不一定唯一了
- 不过即使不唯一,这个最小的权值和一定唯一的
Vertex FindMinDist( MGraph Graph, WeightType dist[] )
{
Vertex MinV, V;
WeightType MinDist = INFINITY;
for (V=0; V<Graph->Nv; V++) {
if ( dist[V]!=0 && dist[V]<MinDist) {
MinDist = dist[V];
MinV = V;
}
}
if (MinDist < INFINITY)
return MinV;
else return ERROR;
}
int Prim( MGraph Graph, LGraph MST )
{
WeightType dist[MaxVertexNum], TotalWeight;
Vertex parent[MaxVertexNum], V, W;
int VCount;
Edge E;
for (V=0; V<Graph->Nv; V++) {
dist[V] = Graph->G[0][V];
parent[V] = 0;
}
TotalWeight = 0;
VCount = 0;
MST = CreateGraph(Graph->Nv);
E = (Edge)malloc( sizeof(struct ENode) );
dist[0] = 0;
VCount ++;
parent[0] = -1;
while (1) {
V = FindMinDist( Graph, dist );
if ( V==ERROR )
break;
E->V1 = parent[V];
E->V2 = V;
E->Weight = dist[V];
InsertEdge( MST, E );
TotalWeight += dist[V];
dist[V] = 0;
VCount++;
for( W=0; W<Graph->Nv; W++ )
if ( dist[W]!=0 && Graph->G[V][W]<INFINITY ) {
if ( Graph->G[V][W] < dist[W] ) {
dist[W] = Graph->G[V][W];
parent[W] = V;
}
}
}
if ( VCount < Graph->Nv )
TotalWeight = ERROR;
return TotalWeight;
}
typedef Vertex ElementType;
typedef Vertex SetName;
typedef ElementType SetType[MaxVertexNum];
void InitializeVSet( SetType S, int N )
{
ElementType X;
for ( X=0; X<N; X++ ) S[X] = -1;
}
void Union( SetType S, SetName Root1, SetName Root2 )
{
if ( S[Root2] < S[Root1] ) {
S[Root2] += S[Root1];
S[Root1] = Root2;
}
else {
S[Root1] += S[Root2];
S[Root2] = Root1;
}
}
SetName Find( SetType S, ElementType X )
{
if ( S[X] < 0 )
return X;
else
return S[X] = Find( S, S[X] );
}
bool CheckCycle( SetType VSet, Vertex V1, Vertex V2 )
{
Vertex Root1, Root2;
Root1 = Find( VSet, V1 );
Root2 = Find( VSet, V2 );
if( Root1==Root2 )
return false;
else {
Union( VSet, Root1, Root2 );
return true;
}
}
void PercDown( Edge ESet, int p, int N )
{
int Parent, Child;
struct ENode X;
X = ESet[p];
for( Parent=p; (Parent*2+1)<N; Parent=Child ) {
Child = Parent * 2 + 1;
if( (Child!=N-1) && (ESet[Child].Weight>ESet[Child+1].Weight) )
Child++;
if( X.Weight <= ESet[Child].Weight ) break;
else
ESet[Parent] = ESet[Child];
}
ESet[Parent] = X;
}
void InitializeESet( LGraph Graph, Edge ESet )
{
Vertex V;
PtrToAdjVNode W;
int ECount;
ECount = 0;
for ( V=0; V<Graph->Nv; V++ )
for ( W=Graph->G[V].FirstEdge; W; W=W->Next )
if ( V < W->AdjV ) {
ESet[ECount].V1 = V;
ESet[ECount].V2 = W->AdjV;
ESet[ECount++].Weight = W->Weight;
}
for ( ECount=Graph->Ne/2; ECount>=0; ECount-- )
PercDown( ESet, ECount, Graph->Ne );
}
int GetEdge( Edge ESet, int CurrentSize )
{
Swap( &ESet[0], &ESet[CurrentSize-1]);
PercDown( ESet, 0, CurrentSize-1 );
return CurrentSize-1;
}
int Kruskal( LGraph Graph, LGraph MST )
{
WeightType TotalWeight;
int ECount, NextEdge;
SetType VSet;
Edge ESet;
InitializeVSet( VSet, Graph->Nv );
ESet = (Edge)malloc( sizeof(struct ENode)*Graph->Ne );
InitializeESet( Graph, ESet );
MST = CreateGraph(Graph->Nv);
TotalWeight = 0;
ECount = 0;
NextEdge = Graph->Ne;
while ( ECount < Graph->Nv-1 ) {
NextEdge = GetEdge( ESet, NextEdge );
if (NextEdge < 0)
break;
if ( CheckCycle( VSet, ESet[NextEdge].V1, ESet[NextEdge].V2 )==true ) {
InsertEdge( MST, ESet+NextEdge );
TotalWeight += ESet[NextEdge].Weight;
ECount++;
}
}
if ( ECount < Graph->Nv-1 )
TotalWeight = -1;
return TotalWeight;
}