华华和月月逛公园
题目链接
题目描述
月月和华华一起去逛公园了。公园很大,为了方便,可以抽象的看成一个N个点M条边的无向连通图(点是景点,边是道路)。公园唯一的入口在1号点,月月和华华要从这里出发,并打算参观所有的景点。因为他们感情很好,走多远都不会觉得无聊,所以所有景点和道路都可以无数次的重复经过。月月发现,有些路可走可不走,有些路则必须要走,否则就无法参观所有的景点。现在月月想知道,有几条路是不一定要经过的。因为这是个很正常的公园,所以没有重边和自环。
输入描述:
第一行两个正整数N和M,表示点数和边数。
接下来M行,每行两个正整数U和V表示一条无向边。
保证给定的图是连通的。
输出描述:
输出一行一个非负整数表示不一定要经过的边有几条。
示例1
输入
5 5
1 2
2 3
3 4
4 5
3 5
输出
3
说明
例如第三条边,月月和华华可以依次走过第一条、第二条、第五条、第四条边走过全部的景点,所以第三条边不一定要经过。同理还有第四条、第五条边,答案为3。
备注:
,
思路:
割边也称作桥,指的是在一个图中,去掉某一条边后,这个图就不联通了。桥就是题中说的一定要走的路,如果不走桥就不能把整个图的景点走遍。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
const int M = 3e5 + 5;
struct edge
{
int to, next;
} e[M << 1];
int head[N], cnt_edge;
int num[N], low[N], idx;
int n, m;
int ans;
inline void addedge(int u, int v)
{
e[cnt_edge] = edge{v, head[u]};
head[u] = cnt_edge++;
e[cnt_edge] = edge{u, head[v]};
head[v] = cnt_edge++;
}
void Tarjan(int cur, int fa)
{
num[cur] = low[cur] = ++idx;
for (int i = head[cur]; ~i; i = e[i].next)
{
int v = e[i].to;
if (v == fa)
continue;
if (!num[v])
{
Tarjan(v, cur);
low[cur] = min(low[cur], low[v]);
if (num[cur] < low[v]) //割边(桥)
ans++;
}
else
low[cur] = min(low[cur], num[v]);
}
}
int main()
{
ios::sync_with_stdio(false), cin.tie(nullptr);
cin >> n >> m;
memset(head, -1, sizeof(head));
for (int i = 0; i < m; i++)
{
int u, v;
cin >> u >> v;
addedge(u, v);
}
Tarjan(1, 0);
cout << m - ans << endl;
return 0;
}