您的位置:首页 > 其它

图论——最小生成树Kruskal算法模板

2018-03-30 20:13 549 查看

 Kruskal算法

   1、算法思想:所有边从小到大依次排序(sort、qsort);依次考查每条边(u,v),有两种情况:     情况1:u和v在同一个连通分量中,那么加入(u,v)后会形成环,因此不能选。     情况2:如果不在一个连通分量,那么加入(u,v)一定是最优解,证明反证法:不加(u,v)存在最小生成树的话,那么加上(u,v)一定有且只有一个环,环中至少有一条边(u’,v’)的权值大于(u,v)的权值。那么删除该边后,得到的新树T’=T+(u,v)-(u’,v’)<= T。所以(u,v)是最优解。(很绕可以略过证明) ?问题1—— 判断任意两个点是否在同一个连通分量,还需要合并两个连通分量。 办法1:暴力 (dfs,bfs),算法效率低 办法2:并查集(Union-Find Set)递归思想:把 X 的父节点保存在P[X]中(如果x没有父节点,则P[X])弊端:假如这棵树是长长的一条链,每次查找就会很慢。可以用压缩路径来优化。2、例题:hdu_1863畅通工程
 以hdu_1863畅通工程为例,Kruskal算法适合稀疏图
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 105
int n,m;//n条边,m个结点
struct road{
int xi,yi,vi;
}rd
;
int par
;//双亲结点
int cmp(road x,road y){
return x.vi<y.vi ;
}
int Unfind(int x){//并查集_查找,压缩路径
if(!par[x])return x;
int i=x;
while(par[i])
i=par[i];
int j=x,temp;
while(par[j]){
temp=par[j];
par[j]=i;
j=temp;
}
return i;
}
int main(){
while(~scanf("%d%d",&m,&n)&&n!=0){
memset(rd,0,sizeof(rd));//初始化结构体
memset(par,0,sizeof(par));//初始化双亲结点
for(int i=0;i<n;i++){
scanf("%d%d%d",&rd[i].xi,&rd[i].yi,&rd[i].vi);
}
sort(rd,rd+n,cmp);
int res=m,ans=0;
for(int i=0;i<n&&res>1;i++){
int nx=Unfind(rd[i].xi);
int ny=Unfind(rd[i].yi);
if(nx!=ny){//不是同一个连通分量合并
res--;
printf("**%d\n",rd[i].vi);
ans+=rd[i].vi;
par[nx]=ny;
}
}
if(res==1)//判断是否能生成树,边数等于结点数减 1
printf("%d\n",ans);
else
printf("?\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: