最小生成树的特点:
(1)MST性质 最小生成树性质:设G=(V,E)是一个连通网络,U是顶点集V的一个真子集。若(u,v)是G中一条“一个端点在U中(例如:u∈U),另一个端点不在U中的边(例如:v∈V-U),且(u,v)具有最小权值,则一定存在G的一棵最小生成树包括此边(u,v)。
算法1:Prime算法,复杂度为o(n^2),与网中的边数无关,所以适合于求边稠密的网的最小生成树。它的算法思想相当于贪心算法,首先从任意顶点Vi开始构造生成树,并将Vi加入到生成树T中,用一个一维数组dist[j]记录其他顶点到Vi的距离,扫描一维数组dist[j],选取值最小的顶点j和相应的边加入T中,再以j为中间点更新Vj顶点到其它的顶点k的距离值,如果dist[k]>map[j][k](map[j][k]为顶点j到k的权值),则更新dist[k]为map[j][k],重复这个操作直到T中有n个顶点。
在构造邻接矩阵的时候如果两个边没有相连的话,直接设这个值为无穷大~~
例题1:NYOJ 38(布线问题),分析:Prime算法,最小与外界相连的费用的楼作为起始点求最小生成树。以这题来具体分析Prime算法的步骤。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; const int MAX=505; #define Inf 10000000 #define CLR(arr,val) memset(arr,val,sizeof(arr)) int num,n,m,cost[MAX],Dist[MAX],visit[MAX],map[MAX][MAX]; int Prime(int pos) { int sum=0;//记录最小生成树的权值 CLR(visit,0);//访问初始化,没有访问的初始化为0 for(int i=1;i<=n;i++) //记录其它顶点到点pos的距离 Dist[i]=map[pos][i]; visit[pos]=1; for(int i=1;i<n;i++)//寻找其它的n-1条边 { int min=Inf;//记录最小的边 for(int j=1;j<=n;j++) if(!visit[j]&&min>Dist[j]) min=Dist[j],pos=j; sum+=min; visit[pos]=1; for(int j=1;j<=n;j++) //如果当前的这个点的邻边比原来Dist[]数组记录的小的话,更新 if(!visit[j]&&Dist[j]>map[pos][j]) Dist[j]=map[pos][j]; } return sum; } int main() { scanf("%d",&num); while(num--) { for(int i=0;i<MAX;i++) fill(map[i],map[i]+MAX,Inf); scanf("%d%d",&n,&m); for(int i=0;i<m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); map[u][v]=map[v][u]=w; } for(int i=1;i<=n;i++) scanf("%d",&cost[i]); int pos=1,min=cost[1]; for(int i=1;i<=n;i++) if(min>cost[i]) min=cost[i],pos=i; printf("%d\n",Prime(pos)+min); } return 0; }
算法2:Kruskal算法,过程为:先将图中的各边按照从小到大的顺序排列,然后遍历该图,找到权值最小的边的顶点,该顶点不能访问过,且不能和以前的边组成回路,这个时候可以用并查集(并查集的知识可以点这里)来判连通,如果满足这两个条件则将该条边加入到最小生成树T中,循环,直到找到n-1条边为止。由于这个算法只与边有关,所以适合于稀疏图。开始看错了,这个行数e要求的是n*(n-1)/2,我一直定义的是505,RE了n次,还是得看清楚题目,代码:
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; const int MAX=125000; #define CLR(arr,val) memset(arr,val,sizeof(arr)) int num,n,m,cost[MAX]; struct Graph{ int a,b,w; friend bool operator<(const Graph &G1,const Graph &G2) { return G1.w<G2.w; } }G[MAX]; class UnionFindSet{ public: void Init() { CLR(father,-1); fill(rank,rank+MAX,1); } int Find(int u) { return father[u]==-1?u:Find(father[u]); } bool Union(int u,int v) { u=Find(u); v=Find(v); if(u==v) return false; if(rank[u]>rank[v]) { rank[u]+=rank[v]; father[v]=u; } else { rank[v]+=rank[u]; father[u]=v; } return true; } private: int father[MAX],rank[MAX]; }UFS; int main() { scanf("%d",&num); while(num--) { UFS.Init(); scanf("%d%d",&n,&m); for(int i=0;i<m;i++) scanf("%d%d%d",&G[i].a,&G[i].b,&G[i].w); sort(G,G+m); int sum=0,count=0; for(int i=0;i<m;i++) { if(UFS.Union(G[i].a,G[i].b)) { sum+=G[i].w; count++; } if(count==n-1) break; } for(int i=0;i<n;i++) scanf("%d",&cost[i]); printf("%d\n",*min_element(cost,cost+n)+sum); } return 0; }
算法3:邻接表+优先队列做法,有关邻接表的模板可以见这里,这个模板是转载自张云聪大神的~,很好用!!直接贴标准程序的代码:
#include<queue> #include<iostream> #include<cstring> #include<cstdio> #include<numeric> #include<algorithm> using namespace std; #define CLR(arr,val) memset(arr,val,sizeof(arr)) struct Node { Node(){} Node(int num,int len):len(len),num(num){} int len,num; }; bool operator<(const Node& n1,const Node& n2) { return n1.len>n2.len; } const int MAX=510; const int MAXE=250000; int Head[MAX],Next[MAXE],Num[MAXE],Len[MAXE]; int Dis[MAX],top; void add(int u,int v,int len) { Num[top]=v; Next[top]=Head[u]; Len[top]=len; Head[u]=top++; } bool InQ[MAX]; int main() { priority_queue<Node> q; int t,m,n,a,b,l; scanf("%d",&t); while(t--) { top=0;CLR(Head,-1); CLR(Dis,0x3f); scanf("%d%d",&m,&n); for(int i=0;i!=n;i++) { scanf("%d%d%d",&a,&b,&l); add(a-1,b-1,l);add(b-1,a-1,l); } Dis[0]=0; q.push(Node(0,0)); while(!q.empty()) { Node t=q.top();q.pop(); if(Dis[t.num]!=t.len) continue; for(int i=Head[t.num];i!=-1;i=Next[i]) { if(Dis[Num[i]]>Len[i]) { Dis[Num[i]]=Len[i]; q.push(Node(Num[i],Len[i])); } } } int minl=0x3f3f3f3f; for(int i=0;i!=m;i++) { scanf("%d",&l); minl=min(minl,l); } printf("%d\n",accumulate(Dis,Dis+m,0)+minl); } return 0; }
Prime算法题目总结:(有待更新)
nyist 38,434;
hdu 1102,1162,1233,1863,1301,1875
poj 1789,2253,2349,1251,1861,2421,2728,2485,1287。。。。