最小生成树及模板题

一个连通图的生成树是一个极小连通子图,其中含有图中的全部顶点和构成一棵树的(n-1)条边。
最小生成树:图中所有生成树中具有边上的权值之和最小的树。
最小生成树是最基本的图论问题之一,可由Kruskal(克鲁斯卡尔)算法和Prim(普里姆)算法求解。
两种算法构造最小生成树的原理不同。
Prim算法核心:从某一顶点出发,每次贪心选择与该点连通且未曾选入的边权最小的顶点加入集合,考虑每次新选入的顶点可能造成的影响,需修改候选边的边权和前驱结点,重复操作,直到选完所有顶点(除初始顶点外,只用选n-1个)。
模板题:http://hihocoder.com/problemset/problem/1097
代码如下:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1005,INF=0x3f3f3f3f;
int n,edge[maxn][maxn];
void init(){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			scanf("%d",&edge[i][j]);//初始化邻接矩阵 
		}
	}
}
int prim(int v){
	int MIN,lowcost[maxn],closest[maxn],k,sum=0;
	for(int i=1;i<=n;i++){
		lowcost[i]=edge[v][i];
		closest[i]=v;
	}
	for(int i=1;i<n;i++){//贪心选择n-1个顶点加入 
		MIN=INF;
		for(int j=1;j<=n;j++){
			if(lowcost[j]&&lowcost[j]<MIN) MIN=lowcost[j],k=j;
		}
		lowcost[k]=0,sum+=MIN;
		for(int j=1;j<=n;j++){//修改侯选边边权和前驱结点 
			if(lowcost[j]&&edge[k][j]<lowcost[j]) lowcost[j]=edge[k][j],closest[j]=k;
		}
	}
	return sum;
}
int main(){
	cin>>n;
	init();
	cout<<prim(1);
	return 0;
}

Kuskal算法核心:与Prim算法相比有一些相似之处,都运用了贪心策略。它是一种按权值的递增次序选择合适的边来构造最小生成树的方法。对图中所有存在的边按递增排序,依次选择,若不能构成回路,表示可以选择,直到选完n-1条边。
并查集:用来判断该边并入后会不会产生环。
模板题:http://hihocoder.com/problemset/problem/1098

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f,maxn=1e6+5;
int n,m,vset[maxn];
struct node{
	int u,v,w;
}a[maxn];
bool cmp(node x,node y){
	return x.w<y.w;
}
int find(int x){//递归寻找根结点 
	if(x==vset[x]) return x;
	else return vset[x]=find(vset[x]);
}
int kruskal(){
	int sum=0,s1,s2;
	sort(a,a+m,cmp);
	for(int i=0;i<n;i++) vset[i]=i;
	for(int i=0;i<m;i++){ 
		s1=find(a[i].u),s2=find(a[i].v);//分别得到两个顶点所属集合编号
		if(s1!=s2) vset[s1]=s2,sum+=a[i].w;//不会形成环,可加入 
	}
	return sum;
}
int main(){
	cin>>n>>m;
	for(int i=0;i<m;i++) scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);//初始化边集 
	cout<<kruskal();
	return 0;
}

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值