[数据结构]第十章-并查集

并查集 : 以不相交集合为基础的抽象数据类型

· 支持运算

1.UFunion(A,B,U):将并查集U中的集合A和B合并,其结果取名为A或B
2.UFfind(e):找出包含元素e的集合,并返回该集合的名字

· 实现思想

每个集合用一棵树表示,树的结点用于存储集合中的元素名和一个指向其父节点的指针,树根结点的元素代表该树所表示的集合。

· 用父节点数组实现

数组 parent[x] 表示元素的父节点。

但在最坏情况下,n个结点的树可能退化为一条链。此时对所有元素各执行一次UFfind耗时O(n^2)。
改进方法:①按结点个数合并(结点少的合并到多的上,用parent[root] = -n记录根为root的树的结点个数n);②按高度合并(高度低的合并到高的上,记录方式同上);③按压缩路径(O(n(α(n))),α(n) < 4)

下面是泡泡的并查集模板

struct UF    
{ 
    int fa[MAX_N]; 
    void init() { for(int i = 1; i < MAX_N; i++) fa[i] = i;} 
    int find(int a) { return fa[a] == a ? a : fa[a] = find(fa[a]);} 
    void mix(int a,int b) { fa[find(a)] = find(b);} 
    bool isSame(int a, int b) { return find(a) == find(b);} 
} uf;

//–作业题

12.4 山海经

这里写图片描述
这里写图片描述

(题目很复杂其实只是想问两节点间的差值,有些已经能判断有些还不能,也即集合间的关系为是否已经能判断差值,能互相判断差值的扔进同一集合。如果AB间差值还不能判断,则语句d A B则把AB集合合并下并且AB结点之间差值为d。如果已经能判断则运算下是否为d以判断真假。差值的算法为,记录下集合中每个结点到根节点的差值qua,那么同一集合中的两节点ab就能通过a-fa-b的路径得到,在合并集合的时候更新a集合根节点的fa为b并且fa的qua通过fa-a-b-fb更新,合并的时候只要更新根节点就好,在find中回溯一边更新其他节点的qua。)

#include<iostream>  
#include<cstdio>  
using namespace std;  
#define MAX 50000+7  
int pre[MAX];  
int qua[MAX];//与pre的犇势差   
int m,n,k,i;  


int find(int x)  
{  
    int t;  
    if(x != pre[x])  
    {  
        t = pre[x];  
        pre[x] = find(pre[x]);  
        qua[x] = (qua[x] + qua[t])%m;  //回溯更新quax   
    }  
    return pre[x];  
}  

void mix(int a, int b,int d)  
{  
    int fa = find(a);  
    int fb = find(b);  
    if(fa != fb)  
        pre[fa] = fb;  
    qua[fa]=(m-qua[a]+d+qua[b])%m;  //fa-a-b-fb 更新quafa   
}  

int main()  
{     
    scanf("%d%d%d",&m,&n,&k);  
    for(i = 1; i <= n; i++)  
    {  
        pre[i] = i;  
        qua[i] = 0;  
    }  

    int d,a,b;  
    int ans = 0;  
    for(i = 1; i <= k; i++)  
    {  
        scanf("%d%d%d",&d,&a,&b);  
        if(a > n || b > n || d >= m )  
        {  
            ans++;  
            continue;  
        }  

        int fa = find(a);  
        int fb = find(b);  
        if(fa == fb)  
        {  
            if((qua[a]+m-qua[b])%m != d)  //a-f-b ab犇势差不为d   
                ans++;  
        }  
        else mix(a,b,d);  
    }  

    printf("%d\n",ans);  
    return 0;  
}

12.2 直通车

这里写图片描述
这里写图片描述
这里写图片描述

(朋友的关系可传递,敌人的关系不可传递。所以用并查集记录朋友关系,用二维数组记录敌人关系即可。)

#include<iostream>  
#include<cstdio>  
using namespace std;  
#define MAX 100+7  

int pre[MAX];  
int mp[MAX][MAX];  
int n,m,k,i,j;  

void init()  
{  
    int i;  
    for(i = 1; i <= n; i++)  
        pre[i] = i;  
}  

int find(int x)  
{  
    int r = x;  
    while(r != pre[r])  
        r = pre[r];  

    int i = x,j;  
    while(i != pre[i])  
    {  
        j = pre[i];  
        pre[i] = r;  
        i = j;  
    }  
    return r;  
}  

void mix(int a, int b)  
{  
    int fa = find(a);  
    int fb = find(b);  
    if(fa != fb)  
        pre[fa] = fb;  
}  

int main()  
{  
    scanf("%d%d%d",&n,&m,&k);  
    init();  

    int x,y,op;  
    for(i = 1; i <= m; i++)  
    {  
        scanf("%d%d%d",&x,&y,&op);  
        mp[x][y] = op;  
        mp[y][x] = op;  
        if(op == 1) mix(x,y);  
    }  

    for(i = 1; i <= k; i++)  
    {  
        scanf("%d%d",&x,&y);  
        int fx = find(x);  
        int fy = find(y);  
        if(fx == fy && mp[x][y] != -1) printf("Good job\n");  
        else if(fx != fy && mp[x][y] != -1) printf("No problem\n");  
        else if(mp[x][y] == -1)  
        {  
            if(fx == fy) printf("OK but...\n");  
            else printf("No way\n");  
        }  

    }  

    return 0;  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值