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

克鲁斯卡尔(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[N],y[N];
int parent[N];//为负数时表示该节点连有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[N],y[N],z[N],r[N];
int parent[N];
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;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值