MST(Minimum Spanning Tree,最小生成树)问题有两种通用的解法,Prim算法就是其中之一,它是从
点的方面
考虑构建一颗MST,大致思想是:设图G顶点集合为U,首先任意选择图G中的一点作为起始点a,将该点加入集合V,再从集合U-V中找到另一点b使得点b到V中任意一点的权值最小,此时将b点也加入集合V;以此类推,现在的集合V={a,b},再从集合U-V中找到另一点c使得点c到V中任意一点的权值
最小,此时将c点加入集合V,直至所有顶点全部被加入V,此时就构建出了一颗MST。因为有N个顶点,所以该MST就有N-1条边,每一次向集合V中加入一个点,就意味着找到一条MST的边。
#include<iostream>
using namespace std;
#define MAX_SIZE 10
#define INF 9999;
typedef char ElemType;
typedef struct Graph
{
int Matrix[MAX_SIZE+1][MAX_SIZE+1];
ElemType v[MAX_SIZE+1];
int vnum,linenum;
}Graph,*G;
int indexof(G &g,ElemType c)
{
for(int i=1;i<=g->vnum;i++)
{
if(c==g->v[i])
{
return i;
}
}
return -1;
}
void create_graph(G &g)
{
g=(G)malloc(sizeof(Graph));
ElemType c1,c2;
int ind1,ind2,weight;
//初始化
for(int i=1;i<=MAX_SIZE;i++)
{
for(int j=1;j<=MAX_SIZE;j++)
{
if(i==j)
{
g->Matrix[i][j]=0;
}else
{
g->Matrix[i][j]=INF;
}
}
}
cout<<"请输入顶点数"<<endl;
cin>>g->vnum;
for(int i=1;i<=g->vnum;i++)
{
cout<<"请输入第"<<i<<"个顶点"<<endl;
cin>>g->v[i];
}
cout<<"请输入总共有多少条边"<<endl;
cin>>g->linenum;
for(int i=1;i<=g->linenum;i++)
{
cout<<"请输入第"<<i<<"条边的两个顶点"<<endl;
cin>>c1;
cin>>c2;
ind1=indexof(g,c1);
ind2=indexof(g,c2);
cout<<"请输入第"<<i<<"条边的权值"<<endl;
cin>>weight;
g->Matrix[ind1][ind2]=weight;
g->Matrix[ind2][ind1]=weight;
}
//打印创建的矩阵
for(int i=1;i<=g->vnum;i++)
{
for(int j=1;j<=g->vnum;j++)
{
cout<<g->Matrix[i][j]<<" ";
}
cout<<endl;
}
}
void prim(G &g)
{
int isUsed[MAX_SIZE+1];//被加入最小生成树的都置1
int lowcost[MAX_SIZE+1];//存储已生成最小生成树中的点的集合到还未加入生成树中的点的集合的最小值,
//如lowcost[i]表示已生成树到未生成的以i为终点的 最小权值
int ind[MAX_SIZE+1];//ind[i]存储到以点i为终点的边的起点下标
//从下标为1的点开始,初始化如下
for(int i=1;i<=MAX_SIZE;i++)
{
isUsed[i]=0;
ind[i]=1;
lowcost[i]=g->Matrix[1][i];
}
isUsed[1]=1;
for(int i=2;i<=g->vnum;i++)
{
int min=INF;
int k;
//找到距离已生成树的点集 具有最小权值的下标k,将其加入到最小生成树点集合
for(int j=1;j<=g->vnum;j++)
{
if(isUsed[j]==0&&lowcost[j]<min)
{
min=lowcost[j];
k=j;
}
}
isUsed[k]=1;
//根据距离点k的最小权值更新lowcost和ind
for(int j=1;j<=g->vnum;j++)
{
if(isUsed[j]==0&&g->Matrix[k][j]<lowcost[j])
{
lowcost[j]=g->Matrix[k][j];
ind[j]=k;
}
}
}
for(int i=1;i<=g->vnum;i++)
{
cout<<"isUsed:"<<isUsed[i]<<" ";
}
cout<<endl;
for(int i=1;i<=g->vnum;i++)
{
cout<<"lowcost:"<<lowcost[i]<<" ";
}
cout<<endl;
for(int i=1;i<=g->vnum;i++)
{
cout<<"ind:"<<ind[i]<<" ";
}
cout<<endl;
}
<span style="word-wrap: break-word; color: rgb(102, 102, 102);font-size:14px; line-height: 24px; font-family: 宋体;">该算法的时间复杂度为</span><span lang="EN-US" style="word-wrap: break-word; color: rgb(102, 102, 102); font-family: 'Times New Roman';font-size:14px; line-height: 24px;"><span style="font-family:Times New Roman;word-wrap: break-word;">O(n2)</span></span><span style="word-wrap: break-word; color: rgb(102, 102, 102);font-size:14px; line-height: 24px; font-family: 宋体;">。与图中边数无关,该算法适合于稠密图。</span>
void main()
{
G g;
create_graph(g);
prim(g);
system("pause");
}
最小,此时将c点加入集合V,直至所有顶点全部被加入V,此时就构建出了一颗MST。因为有N个顶点,所以该MST就有N-1条边,每一次向集合V中加入一个点,就意味着找到一条MST的边。