注:本文算法使用链式前向星数据结构实现。学习链接:链式前向星-学习笔记
一、Prim算法
普通prim算法模板:
//用前向星录数据的时候记得把head初始化为-1 fill(dist,dist+LEN,MAX); memset(vis,0,sizeof vis); int ans=0; dist[1]=0; //如果题目要求输出最小生成树,就把题目要求的源点s的dist设为0 while(1){ //如果题目要求判断最小生成树是否能覆盖所有边,这个循环条件应该是i=n;while(n--)循环n次。 int u=-1,d=MAX;for(i=1;i<=N;i++){if(!vis[i] && dist[i]<d){u=i;d=dist[i];}}if(u<0) break; //如果题目要求判断最小生成树是否能覆盖所有边,出现这样的情况说明不能覆盖所有边。 vis[u]=1;ans+=dist[u];for(i=head[u];~i;i=mp[i].next){ //用前向星遍历u点所有的后继。i是各个后继点在mp的下标,mp[to]是u的各个后继点 int to=mp[i].to;if(!vis[to] && mp[i].w<dist[to]){//如果这个点没有被访问过、并且u->v的路径比点集S到v的路径要短,则更新。 dist[to]=mp[i].w;}} } O("%d\n",ans);
堆优化的prim算法:
堆结构:
struct cmp{bool operator () (int a,int b){return dist[a]>dist[b];} }; priority_queue<int,vector<int>,cmp> pq;
算法代码:
int ans=0; dist[1]=0; pq.push(1); while(!pq.empty()){int u=pq.top();pq.pop();if(vis[u]) continue;vis[u]=1;ans+=dist[u];for(i=head[u];~i;i=mp[i].next){int to=mp[i].to;if(!vis[to] && mp[i].w<dist[to]){dist[to]=mp[i].w;pq.push(to);}} } O("%d\n",ans);
二、Kruskal算法
1.建立边表数据结构
typedef struct edge{int u,v,w;edge(int u=0,int v=0,int w=0):u(u),v(v),w(w){}bool operator < (const edge& obj) const{return w<obj.w;} }edge; edge mp[LEN*LEN];
2.编写并查集模板(以下代码没有写合并的Union操作。这个操作在主代码执行的时候已经实现)
int fa[LEN]; int init(){int i;FF(i,LEN) fa[i]=i; } int findFa(int x){if(x==fa[x]) return x;int r=x;while(r!=fa[r]){r=fa[r];}int t=x;while(x!=fa[x]){t=fa[x];fa[x]=r;x=t;}return r; }
3.编写主代码
sort(mp,mp+cnt); FF(i,cnt){int fa_u=findFa(mp[i].u);int fa_v=findFa(mp[i].v);if(fa_u!=fa_v){ans+=mp[i].w;fa[fa_u]=fa_v;edge_cnt++;if(edge_cnt>=N-1) break;} } O("%d\n",ans);
注意:
①边表的范围要开大,因为边的数目可能是顶点数目的平方(准确说,有向图边树E=N*(N-1) )
②Prim算法在录边的数据的时候,因为是无向图,一条边要录成两条。Kruskal就没有这种必要了。
③各种初始化代码(比如并查集的init() )要注意加上。
打个OJ测试一下吧!
OJ链接:还是畅通工程
AC代码:
#include <stdio.h> #include <memory.h> #include <math.h> #include <string> #include <vector> #include <set> #include <stack> #include <queue> #include <algorithm> #include <map>#define I scanf #define OL puts #define O printf #define F(a,b,c) for(a=b;a<c;a++) #define FF(a,b) for(a=0;a<b;a++) #define FG(a,b) for(a=b-1;a>=0;a--) #define LEN 1010 #define MAX (1<<30)-1 #define V vector<int>using namespace std;int N; int fa[LEN]; int init(){int i;FF(i,LEN) fa[i]=i; } int findFa(int x){if(x==fa[x]) return x;int r=x;while(r!=fa[r]){r=fa[r];}int t=x;while(x!=fa[x]){t=fa[x];fa[x]=r;x=t;}return r; }typedef struct edge{int u,v,w;edge(int u=0,int v=0,int w=0):u(u),v(v),w(w){}bool operator < (const edge& obj) const{return w<obj.w;} }edge; edge mp[LEN*LEN]; int cnt=0;int main(){ // freopen("还是畅通工程.txt","r",stdin);int i,j,u,v,w;while(scanf("%d",&N),N){init();cnt=0;int ans=0;int edge_cnt=0;i=(N*(N-1))/2;while(i--){I("%d%d%d",&u,&v,&w);mp[cnt++]=edge(u,v,w); // mp[cnt++]=edge(v,u,w); }sort(mp,mp+cnt);FF(i,cnt){int fa_u=findFa(mp[i].u);int fa_v=findFa(mp[i].v);if(fa_u!=fa_v){ans+=mp[i].w;fa[fa_u]=fa_v;edge_cnt++;if(edge_cnt>=N-1) break;}}O("%d\n",ans);}return 0; }