题目地址:https://leetcode-cn.com/problems/remove-max-number-of-edges-to-keep-graph-fully-traversable

题目描述

Alice 和 Bob 共有一个无向图,其中包含 n 个节点和 3 种类型的边:

类型 1:只能由 Alice 遍历。
类型 2:只能由 Bob 遍历。
类型 3:Alice 和 Bob 都可以遍历。

给你一个数组 edges ,其中 edges[i] = [typei, ui, vi] 表示节点 uivi 之间存在类型为 typei 的双向边。请你在保证图仍能够被 Alice 和 Bob 完全遍历的前提下,找出可以删除的最大边数。如果从任何节点开始,Alice 和 Bob 都可以到达所有其他节点,则认为图是可以完全遍历的。

返回可以删除的最大边数,如果 Alice 和 Bob 无法完全遍历图,则返回 -1 。

示例 1:

输入:n = 4, edges = [[3,1,2],[3,2,3],[1,1,3],[1,2,4],[1,1,2],[2,3,4]]
输出:2
解释:如果删除 [1,1,2] 和 [1,1,3] 这两条边,Alice 和 Bob 仍然可以完全遍历这个图。再删除任何其他的边都无法保证图可以完全遍历。所以可以删除的最大边数是 2 。

示例 2:

输入:n = 4, edges = [[3,1,2],[3,2,3],[1,1,4],[2,1,4]]
输出:0
解释:注意,删除任何一条边都会使 Alice 和 Bob 无法完全遍历这个图。

示例 3:

输入:n = 4, edges = [[3,2,3],[1,1,2],[2,3,4]]
输出:-1
解释:在当前图中,Alice 无法从其他节点到达节点 4 。类似地,Bob 也不能达到节点 1 。因此,图无法完全遍历。

提示:

  1. 1 <= n <= 10^5
  2. 1 <= edges.length <= min(10^5, 3 * n * (n-1) / 2)
  3. edges[i].length == 3
  4. 1 <= edges[i][0] <= 3
  5. 1 <= edges[i][1] < edges[i][2] <= n
  6. 所有元组 (typei, ui, vi) 互不相同

题目大意

删除最多的边,让两个人最终都能遍历全图。

解题思路

并查集

题目要求最多删除多少条边之后,两人都能完全遍历该图,换句话说,是要保证最终整个图对两个人都是连通的。

我们先讨论简单的情况,假设只有一种类型的边并且只有 1 个人,这种情况下最多删除图中的多少条边,仍然能让此人完全遍历这个图呢?

连通区域的问题,一般都可以使用 并查集 解决。并查集分为 “并”“查” 两部分。“并” 的部分,表示让两个区域连通;“查” 的部分,表示检查两个区域是否连通。本文不详细讲解并查集,但是会在代码部分,分享一个常用的并查集的代码模板。

我们需要遍历每一条边,判断这条边的两个顶点所在区域是否连通(利用了并查集的“查”的功能)。如果两个区域已经连通,说明该边无效,则抛弃该边;否则,说明这条边连通了两个未连通的区域,需要保留该边,且连通这两个区域(利用了并查集的“并”的功能)。

由于本题有两人,所以需要对 Alice 和 Bob 两人分别建一个并查集。我们仍然需要遍历每一条边,由于每个边是有类型的,因此需要根据这条边类型,确定是使用 Alice 的并查集还是 Bob 的并查集。

  • 类型 1:只能由 Alice 遍历,故使用 Alice 的并查集。
  • 类型 2:只能由 Bob 遍历,故使用 Bob 的并查集。
  • 类型 3:Alice 和 Bob 都可以遍历,故使用 Alice 和 Bob 两个人的并查集。

类型 3 的边可以同时连通 Alice 和 Bob 两个人的区域,一条边可以抵得上类型 1 和类型 2 两条边。题目要求最多可以删除多少条边,也就是说最终的图中应该保留最少的边,因此我们想到可以优先保留类型 3 的边。这种策略叫做“贪心”。

至此,本题的解题方法已经清楚了:

  1. 对 Alice 和 Bob 两人分别建一个并查集;

  2. 遍历所有类型 3 的边,分别检查 Alice 和 Bob 的两个并查集,判断此边的两个顶点所在区域是否连通,若不连通则使其连通;若已连通,则可以删除该边;

  3. 遍历所有类型 1 和类型 2 的边,如果是类型 1 则检查 Alice 的并查集,如果是类型 2 则检查 Bob 的并查集,判断此边的两个顶点所在区域是否连通,若不连通则使其连通;若已连通,则可以删除该边。

  4. 判断两个并查集的最终连通区域数是否都为 1。如果都为 1, 说明最终两人的图都是连通的,返回删除了多少边;否则,说明至少一人的图不连通,返回-1.

代码

先分享通用的并查集的模板。来自负雪明烛的博客「代码模板,刷题必会」,地址 https://fuxuemingzhu.blog.csdn.net/article/details/101900729

class DSU:
def __init__(self):
self.par = range(10001)

def find(self, x):
if x != self.par[x]:
self.par[x] = self.find(self.par[x])
return self.par[x] def union(self, x, y):
self.par[self.find(x)] = self.find(y) def same(self, x, y):
return self.find(x) == self.find(y)

对于本题而言,需要改造 union() 函数:如果此边属于同一个区域,那么应该删除此边,返回 1;如果此边属于不同的区域,则此边成功连通了两个区域,返回 0。这样,我们就可以直接对 union() 函数的返回结果求和,统计最终删除了多少条边。

本题的 Python 代码如下:

class Solution(object):
def maxNumEdgesToRemove(self, n, edges):
A = DSU(n)
B = DSU(n)
res = 0
for edge in edges:
if edge[0] != 3:
continue
res += A.union(edge[1], edge[2])
# 这里的结果只用加1次,因为只是1条边
B.union(edge[1], edge[2])
for edge in edges:
if edge[0] == 3:
continue
cur = A if edge[0] == 1 else B
res += cur.union(edge[1], edge[2])
return res if (A.regions() == 1 and B.regions() == 1) else -1 class DSU():
def __init__(self, n):
self.par_ = range(n + 1)
self.regions_ = n

def find(self, x):
if x != self.par_[x]:
self.par_[x] = self.find(self.par_[x])
return self.par_[x] def union(self, x, y):
px = self.find(x)
py = self.find(y)
if px == py:
return 1
self.par_[px] = py
self.regions_ -= 1
return 0 def regions(self):
return self.regions_

参考资料:

  1. 力扣(LeetCode),https://leetcode-cn.com/problems/remove-max-number-of-edges-to-keep-graph-fully-traversable

  2. 花花酱:https://www.bilibili.com/video/BV1PZ4y1N78t

欢迎加入组织

算法每日一题是个互相帮助、互相监督的力扣打卡网站,其地址是 https://www.ojeveryday.com/

想加入千人刷题群的朋友,可以复制上面的链接到浏览器,然后在左侧点击“加入组织”,提交力扣个人主页,即可进入刷题群。期待你早日加入。

公众号:每日算法题

日期

2021 年 1 月 27 日 —— 日更公众号的第3天

【LeetCode】1579. 保证图可完全遍历 Remove Max Number of Edges to Keep Graph Fully Traversable的更多相关文章

  1. PTA 邻接矩阵存储图的深度优先遍历

    6-1 邻接矩阵存储图的深度优先遍历(20 分) 试实现邻接矩阵存储图的深度优先遍历. 函数接口定义: void DFS( MGraph Graph, Vertex V, void (*Visit)( ...

  2. PTA 邻接表存储图的广度优先遍历(20 分)

    6-2 邻接表存储图的广度优先遍历(20 分) 试实现邻接表存储图的广度优先遍历. 函数接口定义: void BFS ( LGraph Graph, Vertex S, void (*Visit)(V ...

  3. leetcode解题报告(2):Remove Duplicates from Sorted ArrayII

    描述 Follow up for "Remove Duplicates": What if duplicates are allowed at most twice? For ex ...

  4. PTA 邻接表存储图的广度优先遍历

    试实现邻接表存储图的广度优先遍历. 函数接口定义: void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) ) 其中LGraph是邻接表存储的 ...

  5. 图的深度优先遍历DFS

    图的深度优先遍历是树的前序遍历的应用,其实就是一个递归的过程,我们人为的规定一种条件,或者说一种继续遍历下去的判断条件,只要满足我们定义的这种条件,我们就遍历下去,当然,走过的节点必须记录下来,当条件 ...

  6. 图的深度优先遍历(DFS) c++ 非递归实现

    深搜算法对于程序员来讲是必会的基础,不仅要会,更要熟练.ACM竞赛中,深搜也牢牢占据着很重要的一部分.本文用显式栈(非递归)实现了图的深度优先遍历,希望大家可以相互学习. 栈实现的基本思路是将一个节点 ...

  7. C语言实现邻接矩阵创建无向图&图的深度优先遍历

    /* '邻接矩阵' 实现无向图的创建.深度优先遍历*/ #include <stdio.h> #include <stdlib.h> #define MaxVex 100 // ...

  8. 图的深度优先遍历(DFS)—递归算法

    实验环境:win10, DEV C++5.11 实验要求: 实现图的深度优先遍历 实验代码: #include <iostream> #define maxSize 255 #includ ...

  9. 数据结构与算法之PHP用邻接表、邻接矩阵实现图的广度优先遍历(BFS)

    一.基本思想 1)从图中的某个顶点V出发访问并记录: 2)依次访问V的所有邻接顶点: 3)分别从这些邻接点出发,依次访问它们的未被访问过的邻接点,直到图中所有已被访问过的顶点的邻接点都被访问到. 4) ...

随机推荐

  1. Python list的深拷贝和浅拷贝

    深拷贝和浅拷贝 列表存储数据,列表拷贝就是数据备份 浅拷贝 优点:占用内存较少 缺点:修改深层数据,会影响原数据 深拷贝 优点:修改数据,互不影响 缺点:占用内存较大 ""&quo ...

  2. doxygen相关命令

    主要配置修改 整个程序配置分几个部分 Project related configuration options 项目相关,包括: 项目名 输出目录 输出语言 是否显示继承属性 是否对C.Java.F ...

  3. Go 类型强制转换

    Go 类型强制转换 强制类型的语法格式:var a T = (T)(b),使用括号将类型和要转换的变量或表达式的值括起来 强制转换需要满足如下任一条件:(x是非常量类型的变量,T是要转换的类型) 1. ...

  4. (转载)SQL Server 2008 连接JDBC详细图文教程

    点评:SQL Server 2008是目前windows上使用最多的sql数据库,2008的安装机制是基于framework重写的,特点是非常耗时间SQL Server 2008是目前windows上 ...

  5. LeetCode子矩形查询

    LeetCode 子矩形查询 题目描述 请你实现一个类SubrectangleQueries,它的构造函数的参数是一个rows * cols的矩形(这里用整数矩阵表示),并支持以下两种操作: upda ...

  6. 日常Java 2021/10/10

    多态就是同一个行为具有多个不同表现形式的能力 多态就是同一个接口,使用不同的实例而执行不同操作 多态的优点 1.消除类型之间的耦合关系 2.可替换性 3.可扩充性 4.接口性 5.灵活性 6.简化性 ...

  7. A Child's History of England.29

    You have not forgotten the New Forest which the Conqueror made, and which the miserable people whose ...

  8. Hbase(二)【shell操作】

    目录 一.基础操作 1.进入shell命令行 2.帮助查看命令 二.命名空间操作 1.创建namespace 2.查看namespace 3.删除命名空间 三.表操作 1.查看所有表 2.创建表 3. ...

  9. react动态添加样式:style和className

    react开发过程中,经常会需要动态向元素内添加样式style或className,那么应该如何动态添加呢??? 一.react向元素内,动态添加style 例如:有一个DIV元素, 需要动态添加一个 ...

  10. 【leetcode】212. Word Search II

    Given an m x n board of characters and a list of strings words, return all words on the board. Each ...