最小生成树的特点:
(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。。。。