您的位置:首页 > 其它

最小生成树(prim&&kruskal)

2018-03-07 12:04 302 查看
下面介绍两种求最小生成树算法

1.Kruskal算法

此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。

1. 把图中的所有边按代价从小到大排序;

2. 把图中的n个顶点看成独立的n棵树组成的森林;

3. 按权值从小到大选择边,所选的边连接的两个顶点ui,vi。ui,vi,应属于两颗不同的树,则成为最小生成树的一条边,并将这两颗树合并作为一颗树。

4. 重复(3),直到所有顶点都在一颗树内或者有n-1条边为止。



Code:

#include<bits/stdc++.h>
#define N 200005
using namespace std;
int ans=0,f
,flag
;
struct node
{
int x,y,z;
}a
;
int cmp(node x,node y)
{
return x.z<y.z;
}
int getfather(int x)
{
if(f[x]==x)return x;else
f[x]=getfather(f[x]);
return f[x];
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
memset(flag,false,sizeof(flag));
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
flag[a[i].x]=true;flag[a[i].y]=true;
}
for(int i=1;i<=n;i++)
if(!flag)
{
puts("orz");
return 0;
}
sort(a+1,a+1+m,cmp);
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=m;i++)
{
int x=a[i].x,y=a[i].y;
x=getfather(x);
y=getfather(y);
if(x!=y)
{
ans+=a[i].z;
f[y]=x;
}
}
printf("%d",ans);
return 0;
}

2.Prim算法

此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。

图的所有顶点集合为V;初始令集合u={s},v=V−u={s};

在两个集合u,v能够组成的边中,选择一条代价最小的边(u,v),加入到最小生成树中,并把u0,v0并入到集合u中。

重复上述步骤,直到最小生成树有n-1条边或者n个顶点为止。

由于不断向集合u中加点,所以最小代价边必须同步更新;需要建立一个辅助数组用来维护集合v中每个顶点与集合u中最小代价边信息:



Code:#include<bits/stdc++.h>
#define N 200005
#define INF 0x3fffffff
using namespace std;
int flag
,f[5005][5005],k
;
int main()
{
int n,m;
scanf("%d%d",&n,&m);
memset(flag,false,sizeof(flag));
memset(f,0x3f,sizeof(f));
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
flag[x]=true;flag[y]=true;
if(z<f[x][y])f[x][y]=f[y][x]=z;
}
for(int i=1;i<=n;i++)
if(!flag)
{
puts("orz");
return 0;
}
for(int i=1;i<=n;i++)k[i]=f[1][i];
k[1]=0;int ans=0;
for(int i=1;i<n;
d6ff
i++)
{
int Min=INF,p;
for(int j=1;j<=n;j++)
if(k[j]&&k[j]<Min)
{
Min=k[j];
p=j;
}
k[p]=0;
ans+=Min;
for(int j=1;j<=n;j++)
k[j]=min(f[p][j],k[j]);
}
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: