link: E. Cyclic Components

E. Cyclic Components

Description:
You are given an undirected graph consisting of n vertices and m edges. Your task is to find the number of connected components which are cycles.

Here are some definitions of graph theory.

An undirected graph consists of two sets: set of nodes (called vertices) and set of edges. Each edge connects a pair of vertices. All edges are bidirectional (i.e. if a vertex a is connected with a vertex b, a vertex b is also connected with a vertex a). An edge can't connect vertex with itself, there is at most one edge between a pair of vertices.

Two vertices u and v belong to the same connected component if and only if there is at least one path along edges connecting u and v.

A connected component is a cycle if and only if its vertices can be reordered in such a way that:

  • the first vertex is connected with the second vertex by an edge,
  • the second vertex is connected with the third vertex by an edge,
  • ...
  • the last vertex is connected with the first vertex by an edge,
  • all the described edges of a cycle are distinct.

A cycle doesn't contain any other edges except described above. By definition any cycle contains three or more vertices.

There are 6 connected components, 2 of them are cycles: [7,10,16] and [5,11,9,15].
Input
The first line contains two integer numbers n and m (1≤n≤2⋅1e5, 0≤m≤2⋅1e5) — number of vertices and edges.

The following m lines contains edges: edge i is given as a pair of vertices vi, ui (1≤vi,ui≤n, ui≠vi). There is no multiple edges in the given graph, i.e. for each pair (vi,ui) there no other pairs (vi,ui) and (ui,vi) in the list of edges.

Output
Print one integer — the number of connected components which are also cycles.

Examples
input
5 4
1 2
3 4
5 4
3 5
output
1
input
17 15
1 8
1 12
5 11
11 9
9 15
15 5
4 13
3 13
4 3
10 16
7 10
16 7
14 3
14 4
17 6
output
2
Note
In the first example only component [3,4,5] is also a cycle.

The illustration above corresponds to the second example.

Problem solving:
这道题的意思就是给你一个有好多部分组成的图,问里面有几个部分是满足条件的。需要满足的条件是这一部分里面所有的点构成一个循环并且每个点最多两个边。(就比如说题目描述的里面的那个图中的[5,11,9,15]一样,就是一个循环的,但是[3,4,13,14]就不行,因为3到4那还有一条边)

其实知道了题意之后很自然的就会想到并查集吧(可能是我这两天一直在做。把每个连通块分开存储,再判断每一块是否满足条件即可。分开存储,我这用了并查集实现,父节点相等就说明在一个连通块中。判断是否满足条件的时候,我们可以用每个顶点的度数来写。因为按照题目中的意思也就是说如果这一部分的所有顶点的度数都是2,才可以满足条件。直接输入的时候预处理一下就行啦。可以看代码注释。

Code:

#include <bits/stdc++.h>
using namespace std;
const int   maxn = 2e5 + 10;
int         n, m, in[maxn], f[maxn], ans, fa[maxn];
vector<int> V[maxn];
int find(int x)
{
    return x != f[x] ? f[x] = find(f[x]) : x;
}
void join(int x, int y)
{
    x = find(x), y = find(y);
    if (x != y)
        f[x] = y;
} //并查集
int main()
{
    ios::sync_with_stdio(0);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        f[i] = i;
    for (int i = 0, u, v; i < m; i++)
    {
        cin >> u >> v;
        in[u]++, in[v]++; //预处理每个结点的度数
        join(u, v);
    }
    for (int i = 1; i <= n; i++)
        find(i);  //这一步是必须有的,因为我们处理的时候每个部分的父节点只有一个来表示,不加这一步的话可能导致明明是一个部分的点却被处理成了两个部分。如果还是不理解,可以注释之后输出f[i]和不注释的时候输出f[i]对比着看看。
    for (int i = 1; i <= n; i++)
    {
        V[f[i]].push_back(i);  //把以f[i]为父节点的点存在一起
    }
    for (int i = 1; i <= n; i++)
    {
        if (V[i].size() == 0) //如果就没有以i为父节点的点,直接跳过
            continue;
        int flag = 1;
        for (int j = 0; j < V[i].size(); j++)
        {
            if (in[V[i][j]] != 2)
            {
                flag = 0;
                break;
            }
        } //如果连通块中的每个节点的度数都是2,答案才能加一
        ans += flag;
    }
    cout << ans << endl;
}