【蓝桥杯】并查集专题


并查集

题库:在线题库_在线做题_智能评测_蓝桥云课题库 - 蓝桥云课 (lanqiao.cn)

1.蓝桥幼儿园(基础并查集)

【题目链接】蓝桥幼儿园 - 蓝桥云课 (lanqiao.cn)

【代码实现】

#include <iostream>
using namespace std;

const int N = 2e6 + 10;
int p[N];
int n, m;

void init()
{
  for(int i = 1; i <= n; i ++) p[i] = i;
}
int find(int x)
{
  if(p[x] != x) p[x] = find(p[x]);
  return p[x];
}
void merge(int a, int b)
{
  if(find(a) != find(b))
    p[find(a)] = find(b);
}

int main()
{
  // 请在此输入您的代码
  cin >> n >> m;
  init();
  while(m --)
  {
    int a, b, opt;
    cin >> opt >> a >> b;
    if(opt == 1) merge(a, b);
    else
    {
      if(find(a) != find(b))
        puts("NO");
       else
        puts("YES"); 
    }
  }

  return 0;
}

2.合根植物(并查集求连通块个数)

【题目链接】合根植物 - 蓝桥云课 (lanqiao.cn)

思路:并查集求连通块个数。

【代码实现】

#include<iostream>
#include<unordered_set> 
#include<set>
using namespace std;

const int N = 1e7 + 10;
typedef long long LL;
int p[N];
int a[N], sizes[N];
int n, m;

// 并查集维护有多少个连通块
void init()
{
  for(int i = 1; i <= n * m; i ++) p[i] = i;
}
int find(int x)
{
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}
void merge(int x, int y)
{
    if(find(x) != find(y))
        p[find(x)] = find(y);
}

int main()
{
    cin >> n >> m;
    init();

    int k;
    cin >> k;
    while(k --)
    {
      int a, b;
      cin >> a >> b;
      merge(a, b);
    }
    
    int sum = 0;
    for(int i = 1; i <= n * m; i ++) 
        if(p[i] == i)
            sum ++;
            
    cout << sum;

    
    return 0;
}

3.七段码(建图+并查集 + dfs(指数类型枚举))

【题目链接】七段码 - 蓝桥云课 (lanqiao.cn)

思路:

每个灯只有两者选择,开或者灭(递归组合类型枚举),暴力枚举七个灯的所有开灭情况,然后并查集维护连通性,若果当前状态开的灯都在一个连通块当中话(连通块个数为1),说明此方案符合要求,反之不然。

建图:

abcdefg

节点编号:1234567

a:1–2,1–6

b:2–1,2–3,2–7

c:3–4,3–2,3–7

d:4–3,4–5

e:5–4,5–6,5–7

f:6–5,6–7,6–1,6–7

g:7–2,7–3,7–5,7–6

【代码实现】

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;


const int N = 10;

int g[N][N];
bool st[N];
int p[N];
int ans;

void init()
{
    g[1][2] = g[1][6] = 1;
    g[2][1] = g[2][3] = g[2][7] = 1;
    g[3][4] = g[3][2] = g[3][7] = 1;
    g[4][3] = g[4][5] = 1;
    g[5][4] = g[5][6] = g[5][7] = 1;
    g[6][1] = g[6][5] = g[6][7] = 1;
    g[7][2] = g[7][3] = g[7][5] = g[7][6] = 1;
}
int find(int x)  // 并查集
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

void merge(int a, int b)
{
    if(find(a) != find(b))
        p[find(a)] = find(b);
}

void dfs(int u)
{
    if(u == 8)// 枚举完七盏灯的情况
    {
        // 注意:因此有多组状态要判断,每次判断时p[]数组要重置!!!
        for (int i = 1; i <= 7; i ++ ) p[i] = i;
        // 将7盏灯中 开的合并
        for (int i = 1; i <= 7; i ++ )
            for (int j = 1; j <= 7; j ++ )
                if(g[i][j] && st[i] && st[j])// 节点i --- 节点j(亮的灯合并)
                    merge(i, j);
                    
        // 判断亮的灯的连通块的个数
        int cnt = 0;
        for(int i = 1; i <= 7; i ++)
            if(st[i] && p[i] == i) cnt ++;
        if(cnt == 1)// 说明只有一个连通块(亮的灯都连通了)
            ans ++;
            
        return ;        
    }
    
    // u这栈灯有亮与不亮两种选择
    
    // 亮
    st[u] = true;
    dfs(u + 1);
    
    // 不亮
    st[u] = false;
    dfs(u + 1);
    
}

int main()
{
    init();
    
    dfs(1);// 从第一栈灯开始
    
    cout << ans;
    
    return 0;
}

4.发现环(并查集判环+dfs图的遍历)

【题目链接】发现环 - 蓝桥云课 (lanqiao.cn)

并查集判断环,当出现环时,令其中一点为起点,另外一点为终点,dfs遍历记录路径。

【代码实现】

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 2e5 + 10;
int p[N], ans[N];
int h[N], e[N], ne[N], idx;
bool st[N];
int n;
int S, T;
void add(int a, int b)  // 添加一条边a->b
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

void init()
{
    memset(st, 0, sizeof st);
    memset(h, -1, sizeof h);
    for(int i = 1; i <= n; i ++) p[i] = i;
}
int find(int x)
{
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}
void merge(int x, int y)
{
    if(find(x) != find(y))
        p[find(x)] = find(y);
}


void dfs(int now, int u)
{
  st[now] = true;
  ans[u] = now;
    
  if(now == T)
  {
    sort(ans, ans + u + 1);
    for(int i = 0; i <= u; i ++) cout << ans[i] << ' ';
    return ;
  }
  for(int i = h[now]; i != -1; i = ne[i])
  {
    int j = e[i];
    if(!st[j])
      dfs(j, u + 1);
    
  }

}

int main()
{
  // 请在此输入您的代码
  cin >> n;
  
  init();
  
  for(int i = 1; i <= n; i ++)
  {
    int a, b;
    cin >> a >> b;
    if(find(a) == find(b))
    {
      S = a, T = b;
    }
    else
    {
       // 无向图
      add(a, b);
      add(b, a);
      merge(a, b);
    }
  }
  dfs(S, 0);
  return 0;
}
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值