代码随想录算法训练营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)
相关推荐
Q8137574601 小时前
中阳视角下的资产配置趋势分析与算法支持
算法
yvestine1 小时前
自然语言处理——文本表示
人工智能·python·算法·自然语言处理·文本表示
GalaxyPokemon1 小时前
LeetCode - 148. 排序链表
linux·算法·leetcode
iceslime2 小时前
旅行商问题(TSP)的 C++ 动态规划解法教学攻略
数据结构·c++·算法·算法设计与分析
aichitang20243 小时前
矩阵详解:从基础概念到实际应用
线性代数·算法·矩阵
OpenCSG3 小时前
电子行业AI赋能软件开发经典案例——某金融软件公司
人工智能·算法·金融·开源
dfsj660114 小时前
LLMs 系列科普文(14)
人工智能·深度学习·算法
薛定谔的算法5 小时前
《盗梦空间》与JavaScript中的递归
算法
kaiaaaa5 小时前
算法训练第十一天
数据结构·算法
?!7145 小时前
算法打卡第18天
c++·算法