并查集

这篇文章是写给克鲁斯算法的并查集,理解的。以前写的啊哈上面的并查集,然后感觉和那个克鲁斯算法的并查集,不一样。(其实本质是一样的,但是啊哈用了递归来写,这个直接写在一个函数上面),因为正在学克鲁斯算法,所以这篇文章会一直更新。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int pre[1010],n,m;
void chushihua()//数组的初始化。
{
    for(int i=0; i<=n; i++)
        pre[i]=i;
    return ;
}
int find1(int x)//这里就是不一样地方,在这个函数当中用while循环去找祖宗,而不是用递归。
{
    int r=x;
    while (pre[r]!=r)
        r=pre[r];
    int i=x,j ;
    while(i!=r)
    {
        j=pre[i];
        pre[i]= r ;
        i=j;
    }
    return r ;
}
void join(int x,int y)//这个是合并,也是一个关键,如果两个人的祖宗不一样,通过这个集合合并成一个集合。
{

    int fx=find1(x);
    int fy=find1(y);
    if(fx!=fy)
        pre[fx ]=fy;

}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        chushihua();
        for(int i=0; i<m; i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            join(x,y);
        }
        int ans=0;
        for(int i=1; i<=n; i++)
            if(pre[i]==i)
                ans++;
        printf("%d\n",ans);
    }
    return 0;
}

下面是克鲁斯卡尔的代码,尤其压缩路径很厉害

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define bian 1010
#define  dian  1010
struct node
{
    int x,y,w;
}b[bian];
int parent[dian];
int n,m;
void cn()//并查集的初始化
{
    for(int i=0;i<=n;i++)
        parent[i]=-1;
}
int find(int x)
{
    int s;
    for(s=x;parent[s]>=0;s=parent[s])
    ;
    while(s!=x)//克鲁斯卡尔的压缩路径,也是并查集的压缩路径方法
    {
        int tmp=parent[x];
        parent[x]=s;
        x=tmp;
    }
    return s;
}
int hebing(int r1,int r2)
{
    int tx=find(r1);
    int ty=find(r2);
    int tmp=parent[tx]+parent[ty];//因为还是最小生成树,于是需要权值的介入
    if(parent[tx]>parent[ty])
    {
        parent[tx]=ty;
        parent[ty]=tmp;
    }
    else
    {
        parent[ty]=tx;
        parent[tx]=tmp;
    }
}
int cmp(node a,node b)
{
    return a.w<b.w;
}
void kruskal()//其实克鲁斯卡尔很好理解
{
    int sumweight=0;
    int num=0;
    int u,v;
    cn();
    for(int i=0;i<m;i++)
    {
        u=b[i].x;
        v=b[i].y;
        if(find(u)!=find(v))
        {
            printf("%d %d  %d\n",u,v,b[i].w);
            num++;
            sumweight+=b[i].w;
            hebing(u,v);
        }
        if(num>=n-1)
            break;
    }
    printf("%d\n",sumweight);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)
    {
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        b[i].x=x;
        b[i].y=y;
        b[i].w=w;
    }
    sort(b,b+m,cmp);
    kruskal();
}
 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值