马上就是另各位oier激(hai)动(pa)的日子——11月10号;
作为复习的日子我今天看了最小生成树,从中的复习:
输入每一条边后再根据边的大小排序,从小的开始弄边,每次从边的两个点是否在集合判断是否在一个集合来看是否可以加入集合
发个简单的prim(堆优化):
#include<bits/stdc++.h> using namespace std; const int INF=0x7ffff/2; int vst[505]; //vst[i]标记顶点i是否加入最小生成树中 int d[505]; //d[i]表示点i与当前生成树中的点有连边的边长最小值 int g[505][505],n,m,ans=0; void Read() { cin>>n>>m; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) g[i][j]=INF; for(int i=1;i<=m;++i) { int x,y,z; cin>>x>>y>>z; g[x][y]=g[y][x]=z; } } void prim(int p) { int minn,k; memset(vst,0,sizeof(vst)); //初始化生成树点集合 for(int i=1;i<=n;++i) d[i]=INF; d[p]=0; ans=0; for(int i=1;i<=n;++i) //选择n个点 { minn=INF; for(int j=1;j<=n;++j) //选择最小边 if(vst[j]==0&&minn>d[j]) { minn=d[j]; k=j; } vst[k]=1; //标记.. ans+=d[k]; for(int j=1;j<=n;++j) //修改d数组 if(vst[j]==0&&d[j]>g[k][j]) d[j]=g[k][j]; } } int main() { Read(); prim(1); cout<<ans<<endl; return 0; } //4 3 //1 2 1 //1 3 1 //1 4 1 //O(n^2)的时间复杂度 可以优化:快速找到权值最小的边--堆; //重点 /*堆优化prim算法:首先我们先想,之前在写prim的时候需要这样做, 从当前的生成树开始,遍历所有可以抵达当前生成树的边,找到一条最短的边, 将该边的权值加到生成树的权值总和上,加该点标记访问,并加到生成树上来。 现在如果我们可以优化方法找到那条最短边的话,那复杂度不就降低了。怎么优化呢? 之前的做法是用一个数组保存每个节点到生成树的距离, 每次找的过程都要遍历一次这个数组。 现在我们用一个优先队列(小根堆)来保存所有可以抵达生成树的边, 每次只要取出该队列的最前面的且合法的边加到生成树 上来就醒了。不合法的边会在这个过程中丢弃! */