Kruskal算法
Kruskal算法是基于贪心的思想得到的。首先我们把所有的边按照权值先从小到大排列,接着按照顺序选取每条边,如果这条边的两个端点不属于同一集合,那么就将它们合并,直到所有的点都属于同一个集合为止。
http://cogs.pro/cogs/problem/problem.php?pid=7
/**************************************************************************************************** 最小生成树(Kruskal) ********************************************************************************************************/ #include<cstdio> #include<algorithm> using namespace std; struct Edge{ int from,to,dist; bool operator <(const Edge a)const{ return dist<a.dist; } }a[1200000]; int mFind[1550]; int Find(int x){//并查集 if(mFind[x]==x)return x; else mFind[x]=Find(mFind[x]); return mFind[x]; } int main(){ freopen("mcst.in","r",stdin); freopen("mcst.out","w",stdout); int n,x,a1=0;scanf("%d",&n); for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ scanf("%d",&x); if(x!=-1&&i<j)a[a1].from=i,a[a1].to=j,a[a1++].dist=x; } } for(int i=0;i<n;i++)mFind[i]=i; sort(a,a+a1);int j=0; //将所有边排序 int fa,fb,u,v,ans=0; for(int i=1;i<n;i++){//将连接两部分的最短边加入生成树 while(1){ u=a[j].from,v=a[j].to; fa=Find(u),fb=Find(v); if(fa!=fb){ ans+=a[j++].dist,mFind[fa]=fb; break; } j++; } } printf("%d",ans); return 0; }
prim算法
其从一个顶点出发,选择这个顶点发出的边中权重最小的一条加入最小生成树中,然后又从当前的树中的所有顶点发出的边中选出权重最小的一条加入树中,以此类推,直到所有顶点都在树中,算法结束。
http://cogs.pro/cogs/problem/problem.php?pid=185
/**************************************************************************************************** 最小生成树(Prim)堆优化 ********************************************************************************************************/ #include<cstdio> #include<algorithm> #include<queue> using namespace std; struct Edge{ int next,to,dist; bool operator <(const Edge a)const{ return dist>a.dist; } }a[100000],s; priority_queue<Edge> t; bool b[305]; int f[305],top=0; inline void add_edge(int from,int to,int dis){ a[++top].next=f[from],a[top].dist=dis,a[top].to=to;f[from]=top; } int main(){ freopen("water.in","r",stdin); freopen("water.out","w",stdout); int n,x; scanf("%d",&n); for(int i=0;i<=n;i++){ for(int j=1;j<=n;j++){ scanf("%d",&x); add_edge(i,j,x); } } int ans=0,v=0;b[0]=1; for(int i=0;i<n;i++){ int to=f[v],u; while(to){ u=a[to].to; if(!b[u]){ t.push(a[to]);//如果边的终点不在生成树中,将边加入优先队列 } to=a[to].next; } s=t.top();t.pop(); u=s.to; while(b[u]){//找出终点不在生成树中权值最小的边 s=t.top();t.pop();u=s.to; } b[u]=1;v=u;ans+=s.dist; } printf("%d",ans); return 0; }