代码随想录算法训练营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)
相关推荐
良月澪二1 小时前
CSP-S 2021 T1廊桥分配
算法·图论
wangyue42 小时前
c# 线性回归和多项式拟合
算法
&梧桐树夏2 小时前
【算法系列-链表】删除链表的倒数第N个结点
数据结构·算法·链表
QuantumStack2 小时前
【C++ 真题】B2037 奇偶数判断
数据结构·c++·算法
今天好像不上班2 小时前
软件验证与确认实验二-单元测试
测试工具·算法
wclass-zhengge3 小时前
数据结构篇(绪论)
java·数据结构·算法
何事驚慌3 小时前
2024/10/5 数据结构打卡
java·数据结构·算法
结衣结衣.3 小时前
C++ 类和对象的初步介绍
java·开发语言·数据结构·c++·笔记·学习·算法
大二转专业5 小时前
408算法题leetcode--第24天
考研·算法·leetcode
凭栏落花侧5 小时前
决策树:简单易懂的预测模型
人工智能·算法·决策树·机器学习·信息可视化·数据挖掘·数据分析