您的位置:首页 > 其它

最小生成树总结

2017-11-26 00:00 239 查看
①Kruskal算法

思想:首先按照边的权值进行从小到大排序,每次从剩余的边中选择权值较小且边的两个顶点不在同一个集合内的边(就是不会产生回路的边),加入到生成树中,直到加入了n-1条边为止。代码如下:

#include<iostream>
#include<algorithm>
using namespace std;

struct edge{
int u;
int v;
int w;
}; //为了方便排序,这里创建了一个结构体用来存储边的关系
int cmp(const edge &x, const edge &y)
{
if(x.w>y.w)
return 0;
else
return 1;
}
struct edge e[10];//数组大小根据实际情况来设置,要比m的最大值加1
int n,m;
int f[7]={0},sum=0;//并查集中需要用到的一些变量
//f数组大小根据实际情况来设置,要比n的最大值大1

//并查集寻找祖先的函数
int getf(int v)
{
if(f[v]==v)
return v;
else
{
f[v]=getf(f[v]);
return f[v];
}
}
//并查集合并两子集合的函数
int merge(int v,int u)
{
int t1,t2;
t1=getf(v);
t2=getf(u);
if(t1!=t2)//判断两个点是否在同一个集合内
{
f[t2]=t1;
return 1;
}
return 0;
}
int main()
{
int i;
int count=0,sum=0;
//读入n和m,n代表顶点个数,m代表边的条数
scanf("%d %d",&n,&m);
//读入边,这里用一个结构体来存储边的关系
for(i=1;i<=m;i++)
{
scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
}
sort(e+1,e+m+1,cmp);//根据权值从小到大排序
//并查集初始化
for(i=1;i<=n;i++)
{
f[i]=i;
}
//kruskal算法核心
for(i=1;i<=m;i++)//从小到大枚举每一条边
{
//判断两条边的两个顶点是否已经连通,即判断是否已在同一个集合中
if(merge(e[i].u,e[i].v))//如果目前尚未不连通则选择这条边
{
count++;
sum=sum+e[i].w;
}
if(count==n-1)
{
break;
}
}
printf("%d",sum);
return 0;
}


②Prim算法

思想:1:从任意一个顶点开始构造树,假设就从1号顶点开始,首先将顶点1加入生成树中,用一个一维数组book来标记哪些顶点已经加入了生成树。

2:用数组dis记录生成树到各个顶点的距离,最初生成树中只有1号顶点,有直连边时,数组dis中存储的就是1号顶点到该顶点的边的权值,没有直连边的时候就是无穷大,即初始化dis数组。

3:从数组dis中选出离生成树最近的顶点(假设这个顶点为j)加入到生成树中(即在数组dis中找到最小值)。再以j为中间点,更新生成树到每一个非生成树顶点的距离(松弛),即如果dis[k]>e[j][k]则更新dis[k]=e[j][k].

4:重复第3步,知道生成树中有n个顶点为止。

#include<stdio.h>
int main()
{
int n,m,i,j,k,min,t1,t2,t3;
int e[7][7],dis[7],book[7]={0};//这里对book数组进行了初始化
int inf=99999999;//充当正无穷
int count=0,sum=0;//count用来记录生成树中顶点的个数,sum用来存储路径之和
//读入n,m表示顶点个数和边的条数
scanf("%d %d",&n,&m);

//初始化
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i==j) e[i][j]=0;
else e[i][j]=inf;

//开始读入边
for(i=1;i<=m;i++)
{
scanf("%d %d %d",&t1,&t2,&t3);
//注意这里是无向图,所以需要将边反向再存储一遍
e[t1][t2]=t3;
e[t2][t1]=t3;
}

//初始化dis数组,这里是1号顶点到各个顶点的初始距离,因为当前生成树中只有1号顶点
for(i=1;i<=n;i++)
{
dis[i]=e[1][i];
}
//将1号顶点加入生成树
book[1]=1;//这里用book来标记一个顶点是否已经加入生成树
count++;
while(count<n)
{
min=inf;
for(i=1;i<=n;i++)
{
if(book[i]==0&&dis[i]<min)
{
min=dis[i];
j=i;
}
}
book[j]=1;
count++;
sum=sum+dis[j];
//扫描当前顶点j所有的边,再以j为中间点,更新生成树到每一个非树顶点的距离。
for(k=1;k<=n;k++)
{
if(book[k]==0&&dis[k]>e[j][k])
dis[k]=e[j][k];
}
}
printf("%d",sum);//打印结果
return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: