2021-12-20 每日打卡:难题精刷

2021-12-20 每日打卡:难题精刷

写在前面

“这些事儿在熟练之后,也许就像喝口水一样平淡,但却能给初学者带来巨大的快乐,我一直觉得,能否始终保持如初学者般的热情、专注,决定了在做某件事时能走多远,能做多好。” 该系列文章由python编写,所刷题目共三个来源:之前没做出来的 ;Leetcode中等,困难难度题目; 周赛题目;某个专题的经典题目,所有代码已AC。每日1-3道,随缘剖析,希望风雨无阻,作为勉励自己坚持刷题的记录。

1192. 查找集群内的「关键连接」

在这里插入图片描述

这个题表达一下,就是寻找联通无向图的桥。顺便吐槽一嘴,其实我的集合论图论还记着,近世代数是真·一塌糊涂,烦,为了考试疲于求生了属于是。哎,到时候抽出时间来再复习得了。这个题使用Tarjan算法,我们先复习一下,集合论的相关知识啊。

  • 割点:去掉点后支数变多(至少大1)
    • 充要条件:v是割点 <-> 存在与v不同的两个顶点w和u,使得v在每一条uw路上 <-> 存在一个二划分{U,W},uw每条路都经过v
    • 性质:最长路的两个端点/叶子不是割点
  • 桥:去掉边后支数变多(1)
    • 充要条件:x是桥 <-> x不在G的任一圈上 <-> 存在不同顶点每条路都经过x <-> 存在二划分
    • 割集:去掉边,能分开,且最少
      • k个支的图去掉割集后变成k+1个支(连通图去掉割集后分成两个支)
      • 割集没有割集子集
      • 连通图中,每个割集至少包含生成树的一条边(从连通->不连通)
      • 连通图中,每个圈与G的任一割集有偶数条公共边(进圈出圈)
      • 相对树的最小割集:即所有相对生成树的桥生成的集合

当然,这里边涉及的还有:

  • 通道和闭通道:顶点和边的的交替序列;起始顶点和结束顶点相同的通道
    • 迹(简单通路)和闭迹(简单回路):不重复的通道和闭通道
    • 路(初级通路)和圈(初级回路/闭路):顶点不重复的通道和闭通道。路和圈一定属于迹和闭迹。
总结一下!圈就是我们通常看到的一个环啊,不在环上的边就是桥!
桥就是我们这里要求的东西!

然后我们就用代码来表达一下,取一个点然后开始dfs,如果碰到已经访问过的点,那就是环!我们怎么区分是第几次来到这个环呢,就是标记一下,最后把每个环上最小的标记作为整个环上的标记。在回溯的过程中,就统一了整个环的标记。

class Solution:
    def criticalConnections(self, n: int, connections: List[List[int]]) -> List[List[int]]:
        # 建图
        graph = collections.defaultdict(list)
        for conn in connections:
            graph[conn[0]].append(conn[1])
            graph[conn[1]].append(conn[0])

        # 建id和返回值
        ids, res = [-1] * n, []
        
        # 定义深度优先
        def dfs(cur_node, cur_id, par):
            # 在探索之前,给你个id
            # 而我的id最终应该取决于所有和我相邻的点的关系
            # 这里给的id只是默认不是环的情况
            ids[cur_node] = cur_id
            
            # 探索相邻节点
            for next_node in graph[cur_node]:
                # 忽略顺着找到自己的那个点
                if next_node == par: 
                    continue
                # 相邻的点,第一次访问,取最小
                # 子结点的id取决于dfs的结果
                elif ids[next_node] == -1:  
                    ids[cur_node] = min(dfs(next_node,cur_id+1,cur_node),ids[cur_node])
                # 有相邻的点,不是第一次访问,取最小,同化自己就可以
                # 也是递归的尽头,找到相邻的点已经被访问过咯
                else: 
                    ids[cur_node] = min(ids[cur_node],ids[next_node])

            # 整理完的最终id == cur_id(不是子结点同化过来的,而是父节点分配的)
            # 是环的脑袋
            # 另外不要忘记 排除特殊(0,0)
            if ids[cur_node] == cur_id and cur_node != 0:
                res.append((par,cur_node))
            return ids[cur_node]
        
        dfs(0,0,0)
        return res
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值