Minimum Spanning tree MST最小生成树 &#lt; template >

总结一下最小生成树,并且放一下模板。

假设 n 表示点数,m 表示边数。

Prim算法

适用条件:

适用于稠密图,时间复杂度 O(n^2)。

核心思想:

每次挑一条与当前集合相连的最短边。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//prim 算法  类似与dijkstra算法   总是维护最小生成树的一部分
//prim 算法适用于稠密图, kruskal算法适用于 稀疏图


//假设现在已经求得的生成树的顶点的集合是x

int cost [max_v][max_v]; //cost[u][v]表示边e=(u,v)的权值(不存在的时候设为inf)
int mincost[max_v]; //从集合x出发的边到每个顶点的最小权值
bool used[max_v]; //顶点i是否包含在集合x中
int V; //顶点数
int prim(){
for(int i = 0; i < V; i++){
mincost[i] = INF;
used[i] = false;
}
mincost[0] = 0;
int res = 0;
while(true){
int v = -1;
//从不属于x的顶点中选取从x到其权值最小的顶点
for(int u = 0; u < V; u++){
if(!used[u] && (v == -1|| mincost[u] < mincost[v]))v = u;
}
if(v == -1 )break;
used[v] = true; //把顶点v加入x
res += mincost[v]; //把边的长度加到结果里
for(int u = 0; u < V;u++){
mincost[u] = min(mincost[u],cost[v][u]);
}
}
return res;
}

堆优化的prim

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//prim 堆优化
// 在不确定有多少条边的时候不好用,建议还是用原始的prim算法
int N,M;//N个点,M个边
const int V_MAX = 100;
const int INF = 1<<31 - 1;

typedef struct edge
{
int to, cost;
edge(int a, int b){
to = a;
cost = b;
}
}edge;
typedef pair<int ,int> P;

vector<edge > G[V_MAX];
int used[V_MAX];

int prim()
{
int sum = 0;
priority_queue<P, vector<P>, greater<P> > pque;
pque.push(P(0,1));

while(!pque.empty())
{
P temp = pque.top();
pque.pop();
int V = temp.second;
int cos = temp.first;
if(used[V])continue;
sum += cos;
used[V] = 1;
for(int i=0; i<G[V].size(); i++)
{
edge e = G[V][i];
pque.push(P(e.cost, e.to));
}
}
return sum;
}

int main()
{
scanf("%d%d",&N,&M);
for(int i=0; i<M; i++)
{
int fir,sec,thi;
scanf("%d%d%d",&fir, &sec, &thi);
G[fir].push_back(edge(sec,thi));
G[sec].push_back(edge(fir,thi));
}
cout << prim() << endl;
}

Kruskal算法

适用条件:

适用于稀疏图,时间复杂度 O(mlogm)。

核心思想:

从小到大挑不多余的边。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const int maxn=1e4+5;
typedef long long LL;
int father[maxn];
struct node
{
int u,v,val;//u-v之间边权为val
}edge[maxn];
bool cmp(node a,node b)//按照边权小到大排序
{
return a.val<b.val;
}
int Find(int x)//并查集查找父节点
{
if(father[x]==x) return father[x];
return father[x]=Find(father[x]);
}
void Union(int x,int y)//合并
{
int fa=Find(x);
int fb=Find(y);
if(fa!=fb) father[fb]=fa;
}
int kruskal(int n,int m)
{
sort(edge,edge+m,cmp);
for(int i=0;i<=n;i++) father[i]=i;//初始化并查集
int ans=0;
for(int i=0;i<m;i++)
{
int fa=Find(edge[i].u);
int fb=Find(edge[i].v);
if(fa!=fb)//如果u,v属于不同集合,进行合并,加入边权
{
Union(edge[i].u,edge[i].v);
ans+=edge[i].val;
}
}
return ans;
}

当时直接套并查集写的,显得有点冗余

题目的话,以后有时间再放。

-------------本文结束感谢您的阅读-------------