最小生成树即在加权连通图里寻找n-1条边,连接n个顶点,并且使得所有边的权重之和最小。最小生成树常用的算法有prim算法和kruskal算法。
1. prim算法
prim算法的基本步骤是:假设图的顶点集合为V,边集合为E,初始化集合U={u},此时集合中只有一个结点u,从u的邻接顶点中选取一个顶点v,使得这两个顶点之间的权重最小,然后把v加入结合U中,再从结点v出发,选取最小权重对应的结点加入集合,循环进行直到所有顶点加入集合。
以上图为例,被访问的结点顺序为1 ,3,4,2,5
最小生成树的权重和为11.,最小生成树用红线标出。
prim算法的程序如下:
# include <iostream>
# include <cstdlib>
using namespace std;
const int Max =0x7fffffff;
const int N=50;
int n;
int g[N][N],dis[N],visited[N];
int prim()
{
int i,j;
int pos,min;
int ans=0;
memset(visited,0,sizeof(visited));
visited[1]=1;pos=1;
for(i=2;i<=n;i++)
dis[i]=g[pos][i];
for(i=1;i<n;i++)
{
min=Max;
for(j=1;j<=n;j++)
if(visited[j]==0&&min>dis[j])
{
min=dis[j];
pos=j;
}
ans+=min;
visited[pos]=1;
for(j=1;j<=n;j++)
if(visited[j]==0&&dis[j]>g[pos][j])
dis[j]=g[pos][j];
}
return ans;
}
int main()
{
int i=1,j=1;
int ans=0;
int w;
cout<<"输入结点数目:"<<endl;
cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(i==j)
g[i][j]=0;
else
g[i][j]=Max;
}
cout<<"输入边的数目:"<<endl;
int edgenum;
cin>>edgenum;
int v1,v2;
cout<<"输入结点编号和对应的权值"<<endl;
for(i=1;i<=edgenum;i++)
{
cin>>v1>>v2>>w;
g[v1][v2]=g[v2][v1]=w;
}
ans=prim();
cout<<ans<<endl;
system("pause");
return 0;
}kruskal算法的基本思想是:先对图中所有边的权重进行排序,然后按照从小到大的顺序,如果这条边的两个顶点不在一个联通分量中,则将这条边加入集合,直到图中所有的顶点都出现在集合中。
也可以这样理解,先把n个顶点看成n棵树,每个数一个结点,每次选取树间的最小边,如果最小边对应的两个顶点不在同一颗树上,那么则合成一颗树,重复n-1步就可以连接n个顶点,得到最小生成树。
kruskan算法的代码是:
#include<iostream>
#include<algorithm>
using namespace std;
struct Edge
{
int a;
int b;
int weight;
}edges[50];
int cmp(const void *a,const void *b)
{
Edge *p=(Edge *)a;
Edge *q=(Edge *)b;
return p->weight-q->weight;
}
int parent[30];
void unionsetset(int root1,int root2)
{
int tmp=parent[root1]+parent[root2];
if(parent[root1]<=parent[root2])
{
parent[root2]=root1;
parent[root1]=tmp;
}
else
{
parent[root1]=root2;
parent[root2]=tmp;
}
}
int find(int v)
{
if(parent[v]==-1)
return v;
else
return parent[v]=find(parent[v]);
}
int main()
{
int n;
cout<<"输入结点数目:"<<endl;
cin>>n;
int edgenum;
cout<<"输入边的数目:"<<endl;
cin>>edgenum;
int i;
for(i=0;i<=n;i++)
parent[i]=-1;
int c1,c2;
for(int i=0;i<edgenum;i++)
{
int w;
cin>>c1>>c2>>w;
edges[i].a=c1;
edges[i].b=c2;
edges[i].weight=w;
}
qsort(edges,edgenum,sizeof(Edge),cmp);
int ans=0;
int count=1;
for(int i=0;i<edgenum;i++)
{
int root1=find(edges[i].a);
int root2=find(edges[i].b);
if(root1!=root2){
unionsetset(root1,root2);
ans+=edges[i].weight;
count++;
if(count==n)
break;
}
}
cout<<ans<<endl;
system("pause");
return 0;
}原文地址:http://blog.csdn.net/u011608357/article/details/30838739