您的位置:首页 > 其它

克鲁斯卡尔算法(kruskal)(并查集的简单应用)

2015-10-23 21:11 295 查看
克鲁斯卡尔(Kruskal)算法(只与边相关)

算法描述:克鲁斯卡尔算法需要对图的边进行访问,所以克鲁斯卡尔算法的时间复杂度只和边又关系,可以证明其时间复杂度为O(eloge)。

算法过程:

1.将图各边按照权值进行排序

2.将图遍历一次,找出权值最小的边,(条件:此次找出的边不能和已加入最小生成树集合的边构成环),若符合条件,则加入最小生成树的集合中。不符合条件则继续遍历图,寻找下一个最小权值的边。

3.递归重复步骤1,直到找出n-1条边为止(设图有n个结点,则最小生成树的边数应为n-1条),算法结束。得到的就是此图的最小生成树。

克鲁斯卡尔(Kruskal)算法因为只与边相关,则适合求稀疏图的最小生成树。而prime算法因为只与顶点有关,所以适合求稠密图的最小生成树。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1005;
struct node
{
int u,v,w;
bool operator< (const node& b) const
{
return w<b.w;
}
};
int n,m;
node edge[maxn];
int parent[maxn];
int k;
void init()
{
k=0;
memset(parent,-1,sizeof(parent));
}
int Find(int num)
{
int s;
for(s=num;parent[s]>=0;s=parent[s]);
while(s!=num)
{
int tmp=parent[num];
parent[num]=s;
num=tmp;
}
return s;
}
int Union(int R1,int R2)
{
int r1=Find(R1);
int r2=Find(R2);
if(r1==r2) return 0;
int tmp=parent[r1]+parent[r2];
//假如r2所含结点数更多
if(parent[r1]>parent[r2])
{
parent[r1]=r2;
parent[r2]=tmp;
}
else
{
parent[r2]=r1;
parent[r1]=tmp;
}
return 1;
}
int main()
{
freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
}
sort(edge+1,edge+m+1);
init();
int num=0;
for(int i=1;i<=m;i++)
{
if(Union(edge[i].u,edge[i].v))
{
k+=edge[i].w;
cout<<edge[i].u<<" "<<edge[i].v<<" "<<edge[i].w<<endl;
num++;
}
if(num>=n-1) break;
}
cout<<k<<endl;
}
return 0;
}


水题,zoj1203:

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1203

题意:给定N各城市位置,计算连接这N个城市的最短路线长度。

计算并储存每对城市的路线长度,用kruskal算法求解,注意输出格式!

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=105;
struct node
{
int u,v;
double w;
bool operator<(const node& b)const
{
return w<b.w;
}
}edge[N*N];
double lg;
double x
,y
;
int parent
;//为负数时表示该节点连有parent【N】-1个结点
int n;
int tmp;
void init()
{
lg=0;
memset(parent,-1,sizeof(parent));
}
int Find(int t)
{
int s=t;
while(parent[s]>=0)
{
s=parent[s];
}
while(t!=s)
{
int tt=parent[t];
parent[t]=s;
t=tt;
}
return s;
}
void Union(node p)
{
int r1=Find(p.u);
int r2=Find(p.v);
int t=parent[r1]+parent[r2];
if(parent[r1]>parent[r2])
{
parent[r1]=r2;
parent[r2]=t;
}
else
{
parent[r2]=r1;
parent[r1]=t;
}
}
void kruskal()
{
int num=0;
for(int i=0;i<tmp;i++)
{
int u=edge[i].u;
int v=edge[i].v;
if(Find(u)!=Find(v))
{
lg+=edge[i].w;
num++;
Union(edge[i]);
}
if(num>=n-1) return;
}
}
int main()
{
//freopen("in.txt","r",stdin);
int ttt=0;
while(cin>>n)
{
if(n==0)
break;
init();
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&x[i],&y[i]);
}
tmp=0;
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
edge[tmp].u=i;
edge[tmp].v=j;
edge[tmp++].w=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
}
sort(edge,edge+tmp);
kruskal();
if(ttt>=1) cout<<endl;
printf("Case #%d:\n",++ttt);
printf("The minimal distance is: %.2lf\n",lg);
}
return 0;
};


水题:zoj1718:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=718

计算两个空间站中心距离d,判断是否交叉或重合(即两空间站半径与d的大小关系),接下来就相当于模板题了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=105;
struct node
{
int u,v;
double w;
bool operator <(const node& b) const
{
return w<b.w;
}
}edge[N*N];
int n;
int lg;
double weight;
double x
,y
,z
,r
;
int parent
;
void init()
{
lg=0;
weight=0;
memset(parent,-1,sizeof(parent));
}
int Find(int tmp)
{
int s=tmp;
while(parent[s]>=0)
{
s=parent[s];
}
while(s!=tmp)
{
int t=parent[tmp];
parent[tmp]=s;
tmp=t;
}
return s;
}
void Union(int u,int v)
{
int r1=Find(u);
int r2=Find(v);
int tmp=parent[r1]+parent[r2];
if(r1>r2)
{
parent[r1]=r2;
parent[r2]=tmp;
}
else
{
parent[r2]=r1;
parent[r1]=tmp;
}
}
void kruskal()
{
int sum=0;
for(int i=0;i<lg;i++)
{
int u=edge[i].u;
int v=edge[i].v;
if(Find(u)!=Find(v))
{
sum++;
weight+=edge[i].w;
Union(u,v);
}
if(sum>=n-1) return;
}
}
int main()
{
//freopen("in.txt","r",stdin);
while(cin>>n)
{
if(n==0)
break;
init();
for(int i=0;i<n;i++)
scanf("%lf%lf%lf%lf",&x[i],&y[i],&z[i],&r[i]);
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
double d=sqrt(pow(x[i]-x[j],2)+pow(y[i]-y[j],2)+pow(z[i]-z[j],2))-r[i]-r[j];
if(d<=0)
d=0;
edge[lg].u=i;
edge[lg].v=j;
edge[lg++].w=d;
}
}
sort(edge,edge+lg);
kruskal();
printf("%.3f\n",weight);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: