代码随想录算法训练营day70 | 108. 冗余连接、109. 冗余连接II

本次题目都来自卡码网

108. 冗余连接

无向图,返回一条可以删去的边,使得结果图是一个有着N个节点的树(即:只有一个根节点)。

  • 从前向后遍历每一条边(因为优先让前面的边连上),边的两个节点如果不在同一个集合,就加入集合(即:同一个根节点)。
  • 如果边的两个节点已经出现在同一个集合里,说明着边的两个节点已经连在一起了,再加入这条边一定就出现环了。
python 复制代码
class UnionFind:
    def __init__(self, n):
        self.n = n
        self.father = [0] * (n + 1)

        for i in range(n + 1):
            self.father[i] = i

    def find(self, u):
        if u == self.father[u]:
            return u
        else:
            self.father[u] = self.find(self.father[u])
            return self.father[u]

    def join(self, u, v):
        u = self.find(u)
        v = self.find(v)
        if u == v:
            return
        else:
            self.father[u] = v

    def is_same(self, u, v):
        u = self.find(u)
        v = self.find(v)
        return u == v


if __name__ == '__main__':
    n = int(input())
    UnionFind = UnionFind(n)
    for i in range(n):
        s, t = map(int, input().strip().split())
        if UnionFind.is_same(s, t):
            print(str(s) + " " + str(t))
            exit()
        else:
            UnionFind.join(s, t)

109. 冗余连接II

1、先考虑节点有两个入度的情况,其中必定有一个是冗余的

2、如果不存在1的情况,则考虑环的情况

python 复制代码
class UnionFind:
    def __init__(self, n):
        self.n = n
        self.father = [0] * (n + 1)

        for i in range(n + 1):
            self.father[i] = i

    def find(self, u):
        if u == self.father[u]:
            return u
        else:
            self.father[u] = self.find(self.father[u])
            return self.father[u]

    def join(self, u, v):
        u = self.find(u)
        v = self.find(v)
        if u == v:
            return
        else:
            self.father[u] = v

    def is_same(self, u, v):
        u = self.find(u)
        v = self.find(v)
        return u == v


# 在有向图里找到删除的那条边,使其变成树
def getRemoveEdge(edges, n):
    union_find = UnionFind(n)  # 初始化并查集
    for i in range(union_find.n):  # 遍历所有的边
        if union_find.is_same(edges[i][0], edges[i][1]):  # 构成有向环了,就是要删除的边
            print(str(edges[i][0]) + " " + str(edges[i][1]))
        else:
            union_find.join(edges[i][0], edges[i][1])


# 删一条边之后判断是不是树
def isTreeAfterRemoveEdge(edges, deleteEdge, n):
    union_find = UnionFind(n)  # 初始化并查集
    for i in range(union_find.n):
        if i == deleteEdge:
            continue
        if union_find.is_same(edges[i][0], edges[i][1]):  # 构成有向环了,一定不是树
            return False
        else:
            union_find.join(edges[i][0], edges[i][1])
    return True


if __name__ == '__main__':
    n = int(input())
    edges = []
    inDegree = [0] * (n + 1)  # 记录节点入度
    for i in range(n):
        s, t = map(int, input().strip().split())
        inDegree[t] += 1
        edges.append((s, t))

    inDegree2 = []  # 记录入度为2的边(如果有的话就两条边)
    # 找入度为2的节点所对应的边,注意要倒序,因为优先删除最后出现的一条边
    for i in range(n - 1, -1, -1):
        if inDegree[edges[i][1]] == 2:
            inDegree2.append(i)
    if len(inDegree2) > 0:
        # 放在inDegree2里的边已经按照倒叙放的,所以这里就优先删inDegree2[0]这条边
        if isTreeAfterRemoveEdge(edges, inDegree2[0], n):
            print(str(edges[inDegree2[0]][0]) + " " + str(edges[inDegree2[0]][1]))
        else:
            print(str(edges[inDegree2[1]][0]) + " " + str(edges[inDegree2[1]][1]))
        exit()
    # 处理情况三
    # 明确没有入度为2的情况,那么一定有有向环,找到构成环的边返回就可以了
    getRemoveEdge(edges, n)
相关推荐
寂静山林2 小时前
UVa 10228 A Star not a Tree?
算法
Neverfadeaway2 小时前
【C语言】深入理解函数指针数组应用(4)
c语言·开发语言·算法·回调函数·转移表·c语言实现计算器
Madison-No73 小时前
【C++】探秘vector的底层实现
java·c++·算法
Swift社区3 小时前
LeetCode 401 - 二进制手表
算法·leetcode·ssh
派大星爱吃猫3 小时前
顺序表算法题(LeetCode)
算法·leetcode·职场和发展
liu****3 小时前
8.list的模拟实现
linux·数据结构·c++·算法·list
地平线开发者4 小时前
征程 6 | 征程 6 工具链如何支持 Matmul/Conv 双 int16 输入量化?
算法·自动驾驶
程序员大雄学编程5 小时前
「深度学习笔记4」深度学习优化算法完全指南:从梯度下降到Adam的实战详解
笔记·深度学习·算法·机器学习
小O的算法实验室6 小时前
2022年ASOC SCI2区TOP,基于竞争与合作策略的金字塔粒子群算法PPSO,深度解析+性能实测,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
南莺莺6 小时前
邻接矩阵的基本操作
数据结构·算法··邻接矩阵