华华和月月逛公园(Tarjan求割边)

华华和月月逛公园

题目链接
题目描述
月月和华华一起去逛公园了。公园很大,为了方便,可以抽象的看成一个N个点M条边的无向连通图(点是景点,边是道路)。公园唯一的入口在1号点,月月和华华要从这里出发,并打算参观所有的景点。因为他们感情很好,走多远都不会觉得无聊,所以所有景点和道路都可以无数次的重复经过。月月发现,有些路可走可不走,有些路则必须要走,否则就无法参观所有的景点。现在月月想知道,有几条路是不一定要经过的。因为这是个很正常的公园,所以没有重边和自环。
输入描述:
第一行两个正整数N和M,表示点数和边数。
接下来M行,每行两个正整数U和V表示一条无向边。
保证给定的图是连通的。
输出描述:
输出一行一个非负整数表示不一定要经过的边有几条。
示例1
输入
5 5
1 2
2 3
3 4
4 5
3 5
输出
3
说明
例如第三条边,月月和华华可以依次走过第一条、第二条、第五条、第四条边走过全部的景点,所以第三条边不一定要经过。同理还有第四条、第五条边,答案为3。
备注:
1 N 1 0 5 1\le N\le 10^5 1 M 3 × 1 0 5 1\le M\le 3\times10^5

思路:
割边也称作桥,指的是在一个图中,去掉某一条边后,这个图就不联通了。桥就是题中说的一定要走的路,如果不走桥就不能把整个图的景点走遍。

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;
}

猜你喜欢

转载自blog.csdn.net/weixin_44169557/article/details/106303110