首页 > 其他分享 >ACWing - 4493 -- 思维题&&并查集&&dfs

ACWing - 4493 -- 思维题&&并查集&&dfs

时间:2022-10-25 22:25:45浏览次数:82  
标签:度数 pre 连通 -- 查集 int && include

题目描述

环形连通分量

思路

对于一个无向图中的 简单环(环中边的数量等于点的数量),有一个很强的性质:每个点的度数等于 \(2\)
那么我们只需要先找出所有的连通块,然后判断每个连通块中的每条边的度数是否位 \(2\) 就可以判断该点所在连通块是不是一个简单环了。

找连通块

求连通块问题是一个图论中的经典问题,我们有三种方法:

  1. 并查集
  2. \(dfs\)
  3. \(bfs\)

其中并查集最简单,代码最短,因此对于求连通块问题优先考虑并查集

代码1:并查集

依据性质:判断每个点的度数是否为2

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

using namespace std;

const int N = 200010;

int n, m;
int pre[N];
bool st[N]; // st[i]=false -> 连通块 i 是简单环,= true -> 不是简单环
int d[N];

int find(int x)
{
    if(pre[x] == x) return x;
    return pre[x] = find(pre[x]);
}

int main()
{
    for(int i = 0; i < N; i ++ )    pre[i] = i;
    cin >> n >> m;
    
    // first. 找到所有连通块,计算每个点的度数
    while(m -- )
    {
        int a, b;
        cin >> a >> b;
        pre[find(a)] = find(b);       // a<-->b,合并到同一个连通块
        d[a] ++ ;       // 度数 ++ 
        d[b] ++ ;       // 度数 ++
    }
    
    // 不要傻乎乎的去真的遍历“每个连通块中”的所有点
    // 那样的话我们还要找到任意连通块中的点集合
    // 只需要直接遍历所有点来判断每个点的度数是否为2就行
    for(int i = 1; i <= n; i ++ )
    {
        if(d[i] != 2)
        {
            st[find(i)] = true;
        }
    }
    
    int res = 0;
    for(int i = 1; i <= n; i ++ )
    {
        if(pre[i] == i && !st[i])  res ++ ;
    }
    cout << res << endl;
    
    return 0;
}

代码2:dfs:

判断每个点是否连了两条边
这其实是对性质:简单环中每个点的度数为 \(2\) 的另外一种表达形式。
每个点的度数为 \(2\) 就等价于每个点连了 \(2\) 条边。
我们这里通过 \(dfs\) 来判断

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

using namespace std;

const int N = 200010, M = N << 1;

int h[N], e[M], ne[M], idx;
int n, m;
bool st[N];

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

bool dfs(int u)
{
    // 标记为已经遍历过,需要放在 dfs[e[i]] 的前面
    st[u] = true;
    
    bool has_res = true;
    int cnt = 0;
    for(int i = h[u]; i != -1; i = ne[i])
    {
        cnt ++ ;
        if(!st[e[i]] && !dfs(e[i]))   has_res = false; // 需要继续dfs下去直到遍历完整个连通块
    }
    return has_res && (cnt == 2);
}

int main()
{
    memset(h, -1, sizeof h);
    cin >> n >> m;
    while (m -- )
    {
        int a, b;
        cin >> a >> b;
        add(a, b);  add(b, a);
    }
    
    // 判断每个点是否连了两条边
    int res = 0;
    for(int i = 1; i <= n; i ++ )
    {
        if(st[i])   continue;
        res += dfs(i);
    }
    
    cout << res << endl;
    return 0;
}

标签:度数,pre,连通,--,查集,int,&&,include
From: https://www.cnblogs.com/ALaterStart/p/16826569.html

相关文章

  • Chap06 回顾数据类型和表达式 第五组
    Chap06回顾数据类型和表达式1)数据存储方式:都是以二进制方式保存,最高位是符号位,0表示正数,1表示负数。 在计算机数据表达中提出了三个重要概念。原码反码补码  原......
  • [论文阅读] Rethinking the Truly Unsupervised Image-to-Image Translation
    pretitle:RethinkingtheTrulyUnsupervisedImage-to-ImageTranslationaccepted:ICCV2021paper:arxiv|ICCVcode:https://github.com/clovaai/tunitref:htt......
  • Codeforces Round #735 (Div. 2) C
    C.Mikasa显然我们应该用log或者O(1)的时间来回答一个ans当n>m时显然我们不能n^m==0所以直接cout0(1)我们知道的是n^i=?那么显然n^?=i(2)然后对于每一个n^i的值是不同的......
  • 2022-10-25学习内容_step01
    1.案例-找回密码-登录界面1.1activity_login_main.xml<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/and......
  • 好看的CSS效果
    好看的效果1.复选框:思路是使用复选框并进行隐藏,然后自己写一个div,并且用:before来放进div复选框这,不少地方采用绝对定位,在:checked时更改对应颜色。<divclass=......
  • 实验2
    1#include<stdio.h>2#include<stdlib.h>3#include<time.h>4#defineN55intmain()6{7intnumber;8inti;9srand(time(0));10......
  • python基础re模块与正则
    正则表达式前戏正则表达式是用来匹配与查找字符串的,从网上爬取数据自然或多或少会用到正则表达式,python的正则表达式要先引入re模块,正则表达式以r引导案例:手机号校验......
  • 【Python】监控笔记本电池状态
    pipinstallpsutilif__name__=='__main__':importpsutilbattery=psutil.sensors_battery()plugged=battery.power_pluggedpercent=str(......
  • CSS
    CSS简介CSS是一门语言,用于控制网页表现CSS:层叠样式表W3C CSS导入方式CSS导入HTML有三种方式内联样式:在标签内部使用style属性,属性值是css属性键值对<divstyle=......
  • 【THM】Nmap Live Host Discovery(nmap存活主机发现)-学习
    本文相关的TryHackMe实验房间链接:https://tryhackme.com/room/nmap01介绍当我们想要定位一个网络时,我们希望找到一个有效的工具来帮助我们处理重复性任务并回答以下问题:......