📜  门|门CS 2008 |问题 24(1)

📅  最后修改于: 2023-12-03 15:28:48.778000             🧑  作者: Mango

题目简介:门 | 门CS 2008 |问题 24

题目描述

给定一张有向图,如果一条边(u, v)满足从点u出发能到达点v,同时从点v出发也能到达点u,则称该边是“双向边”。 现在给定一张有向图,你需要求出其中双向边的数量。

输入格式

第一行包含两个整数,分别表示有向图的节点数N(N<=5000)和边数M(M<=50000)。

接下来M行,每行包含2个整数u,v,表示存在一条从u到v的有向边。

节点编号从1~N。

输出格式

一个整数,表示双向边的数量。

题目分析

对于每条有向边(u, v),我们可以将它看成两条无向边(u, v)和(v, u),然后判断这两条无向边是否都存在,若存在则该有向边就是一条双向边。

常规的判断无向边是否存在的方法是使用邻接表建图进行DFS或BFS遍历,但是这种方法的时间复杂度为O(N*(M+N)),因此不能通过本题。

另外一种O(MlogN)的做法,是将所有边按照起点编号、终点编号排序,然后从前往后枚举每条边,判断其是否是双向边即可。这种做法需要使用一个unordered_map来记录每条无向边是否存在,时间复杂度为O(MlogN)。

参考代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>
using namespace std;

int main()
{
    int n, m;
    cin >> n >> m;
    vector<pair<int, int>> edges;
    unordered_map<int, unordered_map<int, bool>> mp;

    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        edges.push_back({ u, v });
        mp[u][v] = true;
    }

    int res = 0;
    for (const auto& [u, v] : edges) {
        if (mp[u].count(v) && mp[v].count(u)) {
            res++;
        }
    }
    cout << res << endl;

    return 0;
}

该程序使用C++语言实现,思路和上文分析基本一致。使用vector记录所有边,使用unordered_map记录每条无向边是否存在,最后枚举每条边判断是否为双向边,计算双向边数量。