Prim算法——最小生成树
#include <bits/stdc++.h> using namespace std; const int maxn=100000+15; const int maxm=100000+15; struct Edge { int x,y,z,next; Edge(int x=0,int y=0,int z=0,int next=0):x(x),y(y),z(z),next(next) {} }edge[maxm*2]; const bool operator < (const Edge &a,const Edge &b) { return a.z>b.z; } int n,m; int sumedge,head[maxn]; int ins(int x,int y,int z) { edge[++sumedge]=Edge(x,y,z,head[x]); return head[x]=sumedge; } priority_queue <Edge> que; int ans; bool boo[maxn]; int main() { scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); ins(x,y,z); ins(y,x,z); } memset(boo,false,sizeof(boo)); boo[1]=true; for (int u=head[1];u;u=edge[u].next) que.push(edge[u]); for (int i=1;i<n;i++) //总共有n-1条边 { Edge temp; temp=que.top(); for (;boo[temp.y];que.pop(),temp=que.top()); que.pop(); ans+=temp.z; boo[temp.y]=true; for (int u=head[temp.y];u;u=edge[u].next) if (!boo[edge[u].y]) que.push(edge[u]); } printf("%d\n",ans); return 0; }
´我们可以对该算法里面的各个步骤分别考虑:
´初始化:V’={x},E’={},x是随便一个节点;
´这一步只需要随便选取一个点即可;
´重复下列操作,直到V’=V:
´在E集合当中选择最小的边<u,v>使得u∈V’但是v∉V’;
´V’加入节点v,E’加入<u,v>;
´对于上面的第二步,实际上我们只需要对于每一个点维护一个V’集合中的点到达该点的最短距离。
´然后每次扫描一遍数组找到我们所需要的v加入V’;
´复杂度为O(N^2+M).
´对于上面的第二步操作,我们实际上可以通过堆(优先队列)维护一个满足u∈V’但是v∉V’的边集,那么我们就能迅速取出满足要求的边;
´然后当改变了V’的时候,我们就可以根据新加入的节点v对原有的堆进行删除和插入操作。
´需要注意的是,当我们用优先队列实现的时候,我们需要将删除操作延迟。
´复杂度为O((N+M)logN).