1 条题解

  • 0
    @ 2024-11-10 20:52:15

    因为Monster是懒狗,所以题解也很水。

    树是一个连通且无环的无向图,在树中多了一条附加的边之后就会出现环,因此要删去的的边即为导致环出现的边

    可以通过并查集寻找这条边。初始时,每个节点都属于不同的连通分量。遍历每一条边,判断这条边连接的两个顶点是否属于相同的连通分量。

    如果两个顶点属于不同的连通分量,则说明在遍历到当前的边之前,这两个顶点之间不连通,因此当前的边不会导致环出现,合并这两个顶点的连通分量。

    如果两个顶点属于相同的连通分量,则说明在遍历到当前的边之前,这两个顶点之间已经连通,因此当前的边导致环出现,将当前的边作为答案返回。

    时间复杂度:O(nlogn)O(nlogn),其中nn是图中的节点个数。需要遍历图中的nn条边,对于每条边,需要对两个节点查找祖先,如果两个节点的祖先不同则需要进行合并,需要进行 2 次查找和最多 1 次合并。一共需要进行2n2n次查找和最多nn次合并,因此总时间复杂度是O(2nlogn)=O(nlogn)O(2nlogn)=O(nlogn)。这里的并查集使用了路径压缩,但是没有使用按秩合并,最坏情况下的时间复杂度是O(nlogn)O(nlogn),平均情况下的时间复杂度依然是O(nα(n))O(nα(n)),其中αα为阿克曼函数的反函数,α(n)α(n)可以认为是一个很小的常数。

    空间复杂度:O(n)O(n),其中nn是图中的节点个数。使用数组fafa记录每个节点的祖先。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int find(int x, vector<int> &fa) { return x == fa[x] ? x : fa[x] = find(fa[x], fa); }
    int main()
    {
        int n, x, y;
        cin >> n;
        vector<int> fa(n + 1, 0);
        for (int i = 1; i <= n; i++)
            fa[i] = i;
        for (int i = 0; i < n; i++) {
            cin >> x >> y;
            if (find(x, fa) != find(y, fa))
                fa[find(x, fa)] = find(y, fa);
            else {
                cout << x << " " << y << endl;
                break;
            }
        }
        return 0;
    }
    
    • 1

    信息

    ID
    257
    时间
    1000ms
    内存
    256MiB
    难度
    6
    标签
    (无)
    递交数
    48
    已通过
    17
    上传者