题目
You are given an undirected graph consisting of
n
vertices and
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
Two vertices
u
and
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,
Input
The first line contains two integer numbers n
and m (
1≤n≤2⋅105,0≤m≤2⋅105
) — number of vertices and edges.
The following
m
lines contains edges: edge
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.
分析
【题意】
规定了一个简单环,除了在环上的边以外不能有任何其他边。求环的个数。
【思路】
题目规定的简单环是一个很强的条件,对于每一片连通的点,假如有一个点的度不是2,那么即使能构成环,也会因为这里多了一条边导致最终不是符合要求的简单环;而对于一个环中的每个点,至少要有2条边。所以只需要检查所有连通起来的点,只要它们的度都是2,那么它们一定能构成一个简单环;否则把这一片从集合中删去,不再考虑它们。
【注意】
需要考虑二元环的处理,由于是在无向图上的环,不能使用把vis标记为-1的检查环的方法;其实由于这里的环很特殊,不是环的一定会在遍历完整个连通的集合前退出,所以只需要遍历到连通集的最后一个点,就已经足够说明当前的是满足条件的环了,用一个vis来标记访问过的点就能实现。
为了避免重复计数(由于手速慢时间不够),可以再用一个clr数组来表示哪些点已经是不用再处理的了,每处理一个连通集,就把它加入到clr数组,以降低复杂度。
代码
#include<stdio.h>
#include<vector>
using std::vector;
#define N_max 200005
int n,m;
vector<int> node[200005];
//记录访问过点的数组和已经删除了的点的数组
vector<int> vis,clr;
//检查某一片是否满足简单环
int dfs(int cur) {
vis[cur] = 1;
int sz = node[cur].size();
if (sz != 2)return 0;
for (int i = 0; i < sz; ++i) {
if (vis[node[cur][i]] == 1)continue;
//不是环,提前退出
if (0 == dfs(node[cur][i]))
return 0;
}
//没有可以继续搜索的点,说明是环
return 1;
}
void clear(int cur) {
//使用dfs删除该连通集
clr[cur] = 1;
int sz = node[cur].size();
for (int i = 0; i < sz; ++i) {
if (clr[node[cur][i]] == 1)continue;
clear(node[cur][i]);
}
}
int main() {
int a1, a2;
scanf("%d %d", &n, &m);
vis.resize(n+1);
clr.resize(n + 1);
for (int i = 0; i < m; ++i) {
scanf("%d %d", &a1, &a2);
node[a1].emplace_back(a2);
node[a2].emplace_back(a1);
}
int sum = 0;
for (int i = 1; i <= n; ++i) {
if (clr[i] == 0)
{
vis.resize(n+1);
sum += dfs(i);
//不论是不是环都要删除
clear(i);
}
}
printf("%d\n", sum);
}