Leetcode 2123. 使矩阵中的 1 互不相邻的最小操作数
1.题目基本信息
1.1.题目描述
给你一个 下标从 0 开始 的矩阵 grid。每次操作,你可以把 grid 中的 一个 1 变成 0 。
如果一个矩阵中,没有 1 与其它的 1 四连通(也就是说所有 1 在上下左右四个方向上不能与其他 1 相邻),那么该矩阵就是 完全独立 的。
请返回让 grid 成为 完全独立 的矩阵的 最小操作数。
1.2.题目地址
https://leetcode.cn/problems/minimum-operations-to-remove-adjacent-ones-in-matrix/description/
2.解题方法
2.1.解题思路
二分图+匈牙利算法求二分图的最大匹配数
二分图+Hopcroft-karp算法求二分图的最大匹配数
2.2.解题步骤
二分图+匈牙利算法步骤
-
第一步,构建二分图。在所有值为1的结点中,其中偶数下标行的偶数下标结点和奇数下标行的奇数下标结点为左结点集合uSet,其余结点为右结点集合vSet;uSet和vSet中彼此相邻代表一条边
-
第二步,执行匈牙利算法获取最大匹配数
- 匈牙利算法的步骤请看代码注释
二分图+Hopcroft-karp算法步骤
-
第一步,构建二分图。在所有值为1的结点中,其中偶数下标行的偶数下标结点和奇数下标行的奇数下标结点为左结点集合uSet,其余结点为右结点集合vSet;uSet和vSet中彼此相邻代表一条边
-
第二步,执行二分图+Hopcroft-karp算法获取最大匹配数
- Hopcroft-karp算法的步骤请看代码注释
3.解题代码
二分图+匈牙利算法代码
# ==> 匈牙利算法
# params:graph:二分图的邻接表;leftNodes:二分图左集合的所有结点数组
# return:返回二分图中的最大匹配数(等于最小点覆盖数)
from collections import defaultdict
def hungarian(graph:dict[int,list[int]], leftNodes:list[int]) -> int:# 第一步,构建维护变量。rightMatch维护右集合中各个结点的匹配状态rightMatch = {}# 第二步,构建dfs递归函数。递归任务:判断左集合中结点u是否能成功匹配。如果u相邻结点v没有匹配,则直接匹配;如果v已经匹配,则将v标记为已访问,dfs(match[v])观察是否能让match[v]结点匹配非v结点来释放v结点,让u进行匹配,即贪心地进行匹配。def dfs(u:int) -> bool:# 2.1.枚举u的相邻的右集合结点vfor v in graph[u]:# 2.2.判断v是否已访问,已访问则跳过if not visited[v]:# 2.3.标记v为已访问,并根据条件判断是否能匹配,能匹配的情况下记录右结点v的匹配状态到rightMatch中visited[v] = Trueif v not in rightMatch or dfs(rightMatch[v]):rightMatch[v] = ureturn True# 2.4.如果最终都没能匹配一个,则返回Falsereturn False# 第三步,枚举每一个左集合结点u,调用dfs判断各个u结点是否能成功进行匹配,并记录最大匹配数到ans中ans = 0for u in leftNodes:visited = defaultdict(bool)if dfs(u):ans += 1return ansclass Solution:def getGraphAndNodes(self, grid: List[List[int]]):m, n = len(grid), len(grid[0])# 第一步,构建二分图。在所有值为1的结点中,其中偶数下标行的偶数下标结点和奇数下标行的奇数下标结点为左结点集合uSet,其余结点为右结点集合vSet;uSet和vSet中彼此相邻代表一条边graph = defaultdict(list)leftNodes, rightNodes = [], []for i in range(m):for j in range(n):if grid[i][j] == 1:# 1.1.将结点添加到图中node = i * n + jif (i % 2 == 0 and j % 2 == 0) or (i % 2 == 1 and j % 2 == 1):leftNodes.append(node)else:rightNodes.append(node)graph[node] = []# 1.2.将边添加到图中for dr, dc in [[-1, 0], [0, -1], [1, 0], [0, 1]]:nr, nc = i + dr, j + dcif 0 <= nr < m and 0 <= nc < n and grid[nr][nc] == 1:node2 = nr * n + ncgraph[node].append(node2)# print(graph)return graph, leftNodes, rightNodes# 思路1【超时】:二分图+匈牙利算法。题目转换:等价于求二分图的最大匹配数def minimumOperations(self, grid: List[List[int]]) -> int:graph, leftNodes, _ = self.getGraphAndNodes(grid)# 第二步,执行匈牙利算法获取最大匹配数return hungarian(graph, leftNodes)
二分图+Hopcroft-karp算法代码
# ==> 匈牙利算法
# params:graph:二分图的邻接表;leftNodes:二分图左集合的所有结点数组
# return:返回二分图中的最大匹配数(等于最小点覆盖数)
from collections import defaultdict
def hungarian(graph:dict[int,list[int]], leftNodes:list[int]) -> int:# 第一步,构建维护变量。rightMatch维护右集合中各个结点的匹配状态rightMatch = {}# 第二步,构建dfs递归函数。递归任务:判断左集合中结点u是否能成功匹配。如果u相邻结点v没有匹配,则直接匹配;如果v已经匹配,则将v标记为已访问,dfs(match[v])观察是否能让match[v]结点匹配非v结点来释放v结点,让u进行匹配,即贪心地进行匹配。def dfs(u:int) -> bool:# 2.1.枚举u的相邻的右集合结点vfor v in graph[u]:# 2.2.判断v是否已访问,已访问则跳过if not visited[v]:# 2.3.标记v为已访问,并根据条件判断是否能匹配,能匹配的情况下记录右结点v的匹配状态到rightMatch中visited[v] = Trueif v not in rightMatch or dfs(rightMatch[v]):rightMatch[v] = ureturn True# 2.4.如果最终都没能匹配一个,则返回Falsereturn False# 第三步,枚举每一个左集合结点u,调用dfs判断各个u结点是否能成功进行匹配,并记录最大匹配数到ans中ans = 0for u in leftNodes:visited = defaultdict(bool)if dfs(u):ans += 1return ans# ==> Hopcroft-karp算法(时间复杂度:O(sqrt(V)*E))
# params:graph:二分图的邻接表;leftNodes:二分图左集合的所有结点数组;
# return:返回二分图中的最大匹配数(等于最小点覆盖数)
from collections import deque
def hopcroftKarp(graph:dict[int, list[int]], leftNodes:list[int]) -> int:inf = float("inf")# 第一步,构建维护变量。match_维护二分图中各个匹配关系;dist维护各个交替路中距离左集合中未匹配点的最短距离,dist中映射值为inf代表结点已经匹配或者不存在以该结点开头的增广路径match_ = {}dist = {}# 第二步,构建广搜函数。bfs功能:返回在match_和dist的情况下,是否还存在更多的增广路径,同时更新distdef bfs() -> bool:# 2.1.将左侧集合的未匹配结点全部加入到队列中,作为BFS的起点;同时将左集合中已经匹配的结点的距离值设置为infque = deque()for u in leftNodes:if u not in match_:que.append(u)dist[u] = 0else:dist[u] = inf# 2.2.广搜二分图。使用found维护图中是否还存在增广路径found = Falsewhile que:u = que.popleft()for v in graph[u]:if v not in match_:# 2.2.1.如果右侧结点v没有在match_中,说明v结点还没有匹配,表示图中还存在增广路径,设置found=Truefound = Trueelif dist[match_[v]] == inf:# 2.2.2.如果右侧结点v在match_中且对应的match_[v]结点还没有被广搜到(即dist[match_[v]==inf]),说明v结点已经匹配,则将v的匹配结点match_[v]加入到广搜队列中,继续寻找增广路径;并更新match_[v]结点所在的最小广搜层次que.append(match_[v])dist[match_[v]] = dist[u] + 1# 2.3.返回图中是否还存在增广路径return found# 第三步,构建受限深搜函数。深搜任务:判断以结点u开头是否存在增广路径;如果存在,则在该路径上进行结点匹配,反转该增广路径。def dfs(u:int) -> bool:for v in graph[u]:if v not in match_ or (dist[match_[v]] == dist[u] + 1 and dfs(match_[v])):# 3.1.如果结点v没有匹配,则u->v就是最短的增广路径,直接匹配u和v并返回即可;如果结点v已经匹配了,只有满足match_[v]是广搜中结点u的下一层级时(即dist[match_[v]]==dist[u]+1)(这个条件也能过滤掉递归时match_[v]遍历到相邻结点v的情况),才能继续dfs判断是否存在增广路径,如果存在则匹配并反转该增广路径match_[u] = vmatch_[v] = ureturn True# 3.2.如果不存在以u开头的增广路径,则在dist中进行标记,并返回Falsedist[u] = infreturn False# 第四步,循环地进行bfs判断图中是否存在增广路径;如果存在则遍历所有左侧没有匹配的结点u,dfs寻找是否存在u开头的最短增广路径,并在dfs中更新match_和dist,如果存在以u开头的增广路径,则通过反转增广路径进行匹配,并将ans自增1ans = 0while bfs():for u in leftNodes:if u not in match_ and dfs(u):ans += 1return ansclass Solution:def getGraphAndNodes(self, grid: List[List[int]]):m, n = len(grid), len(grid[0])# 第一步,构建二分图。在所有值为1的结点中,其中偶数下标行的偶数下标结点和奇数下标行的奇数下标结点为左结点集合uSet,其余结点为右结点集合vSet;uSet和vSet中彼此相邻代表一条边graph = defaultdict(list)leftNodes, rightNodes = [], []for i in range(m):for j in range(n):if grid[i][j] == 1:# 1.1.将结点添加到图中node = i * n + jif (i % 2 == 0 and j % 2 == 0) or (i % 2 == 1 and j % 2 == 1):leftNodes.append(node)else:rightNodes.append(node)graph[node] = []# 1.2.将边添加到图中for dr, dc in [[-1, 0], [0, -1], [1, 0], [0, 1]]:nr, nc = i + dr, j + dcif 0 <= nr < m and 0 <= nc < n and grid[nr][nc] == 1:node2 = nr * n + ncgraph[node].append(node2)# print(graph)return graph, leftNodes, rightNodes# 思路2:二分图+Hopcroft-karp算法def minimumOperations(self, grid: List[List[int]]) -> int:graph, leftNodes, rightNodes = self.getGraphAndNodes(grid)# 计算最大匹配数maxMatching = hopcroftKarp(graph, leftNodes)return maxMatching
4.执行结果
相关文章:

Leetcode 2123. 使矩阵中的 1 互不相邻的最小操作数
1.题目基本信息 1.1.题目描述 给你一个 下标从 0 开始 的矩阵 grid。每次操作,你可以把 grid 中的 一个 1 变成 0 。 如果一个矩阵中,没有 1 与其它的 1 四连通(也就是说所有 1 在上下左右四个方向上不能与其他 1 相邻)&#x…...

MySQL高可用集群
https://dev.mysql.com/doc/mysql-shell/8.4/en/mysql-innodb-cluster.html 1 什么是MySQL高可用集群 MySQL高可用集群:MySQL InnoDB ClusterInnoDB Cluster是MySQL官方实现高可用读写分离的架构方案,包含以下组件 MySQL Group Replication:简…...

day14 leetcode-hot100-27(链表6)
21. 合并两个有序链表 - 力扣(LeetCode) 1. 暴力法 思路 创建一个空节点,用来组装这两个链表,谁小谁就是下一个节点。 知识 创建空节点:ListNode n1 new ListNode(-1); 具体代码 /*** Definition for singly-l…...

YOLOv5 :训练自己的数据集
- **🍨 本文为[🔗365天深度学习训练营](https://mp.weixin.qq.com/s/rnFa-IeY93EpjVu0yzzjkw) 中的学习记录博客** - **🍖 原作者:[K同学啊](https://mtyjkh.blog.csdn.net/)** 我们接着上一篇文章配置完YOLOv5需要的环境后&#…...

flutter项目迁移空安全
重中之重 备份好项目文件,甚至连已经加载好的flutter库也可以备份。环境包升级 2.1 不要直接换成flutter:3.0以上的版本,这样做既有基本的库兼容问题,又有空安全下的语法问题(整个项目中需要增加 late、?、!的语法错误,一片报错的…...
vue element日期范围选择器只能选择指定天数内的
<el-date-pickerv-model"dateRange"type"daterange"range-separator"至"start-placeholder"开始日期"end-placeholder"结束日期"format"yyyy-MM-dd"value-format"yyyy-MM-dd"clearable:picker-optio…...
从 AMQP 到 RabbitMQ:核心组件设计与工作原理(二)
五、RabbitMQ 工作原理全揭秘 在深入了解了 RabbitMQ 的核心组件之后,接下来让我们深入探究 RabbitMQ 的工作原理,揭开其在消息生产、投递、消费以及可靠性保障等方面的神秘面纱。 5.1 消息生产与投递流程 建立连接与信道:生产者首先通过 …...

MySql(十二)
目录 MySql约束 1.添加主键约束 语法格式 1)创建一个带主键的表 查看表结构 2)创建表的时候指定主键名称 查看表结构 3)创建一个表然后,然后再使用alter为列添加主键 查看表结构 4)为表添加数据 1---正常数据 2---主键…...

51c视觉~3D~合集3
我自己的原文哦~ https://blog.51cto.com/whaosoft/13954440 #SceneTracker 在4D时空中追踪万物!国防科大提出首个长时场景流估计方法 本篇分享 TPAMI 2025 论文SceneTracker: Long-term Scene Flow Estimation Network,国防科大提出首…...
windows11安装编译QtMvvm
windows11安装编译QtMvvm 1 从github下载代码2 官方的Download/Installtion3 自行构建编译QtMvvm遇到的问题3.1 `qmake`问题执行命令报错原因分析qmake报错:找不到编译器 cl解决方案3.2 `make qmake_all`问题执行命令报错原因分析make命令未识别解决方案3.3 缺少`perl`问题执行…...

【2025年电工杯数学建模竞赛A题】光伏电站发电功率日前预测问题+完整思路+paper+源码
本人7年数学建模竞赛经验,历史获奖率百分之百。团队成员都是拿过全国一等奖的硕博,有需要数模竞赛帮助的可以私信我 本题主要涉及数据预测,数据分析,机器学习,时间序列等知识 1.问题背景与问题描述 2.解题思路分析 …...

OpenCv高阶(十九)——dlib关键点定位
文章目录 一、什么是人脸关键点定位?二、关键点模型的下载及关键信息的理解三、dlib关键点定位的简单实现(1)导入必要的库(2)从指定路径读取图像文件(3)创建dlib的正面人脸检测器对象࿰…...

BUUCTF之[ACTF2020 新生赛]BackupFile
打开环境就一句话 找出源文件! 结合题目名字:BackupFile 先用dirsearct扫描网站文件 发现一个index.php.bak ,拼接url下载 打开发现php代码 <?php include_once "flag.php";if(isset($_GET[key])) {$key $_GET[key];if(!is_numeric($key)) {exit…...

头歌之动手学人工智能-Pytorch 之autograd
目录 第1关:Variable 任务描述 编程要求 测试说明 没有伟大的愿望,就没有伟大的天才。——巴尔扎克开始你的任务吧,祝你成功! 第2关:Variable 属性 任务描述 编程要求 测试说明 真正的科学家应当是个幻想家&a…...
OIer常用的软件
前言 现在许多软件的官网多不好找,所以我今天就将常用的一些软件官网地址翻了出来,并简单介绍了他的用法。 正文 1.DEV-C DEV-C 用途:c编译软件,是OIer的生涯之路的必备软件 2.Katex KATex 用途:展现公式的软件&…...
Centos7.x内网环境Jenkins前端打包环境配置
Centos7.x内网环境Jenkins前端打包环境配置 参考地址: https://www.cnblogs.com/guangdelw/p/18763336 https://2048.csdn.net/682c1be8606a8318e857d687.html 前言:环境描述和目标 最近公司新接了一个项目,要求是:需要再桌面…...

Kafka集成Flume/Spark/Flink(大数据)/SpringBoot
Kafka集成Flume Flume生产者 ③、安装Flume,上传apache-flume的压缩包.tar.gz到Linux系统的software,并解压到/opt/module目录下,并修改其名称为flume Flume消费者 Kafka集成Spark 生产者 object SparkKafkaProducer{def main(args:Array[S…...

Scratch节日 | 拯救屈原 | 端午节
端午节快乐! 这款特别为端午节打造的Scratch游戏 《拯救屈原》,将带你走进古代中国,感受历史与文化的魅力! 🏮 游戏介绍 扮演勇敢的探险者,穿越时空回到古代,解锁谜题,完成任务&…...

rabbitmq Direct交换机简介
在实际开发中,需求可能变得复杂,如消息的收发和处理。以支付系统为例,成功支付后需要改变订单状态并通知用户,而失败则不需要。为处理这种情况,提出了使用Direct交换机,它可以根据规则将消息路由到指定队列…...

Git实战--基于已有分支克隆进行项目开发的完整流程
Git克隆项目开发流程 ✅ 一、完整流程概述✅ 二、详细操作步骤Step 1:克隆仓库(如果尚未克隆)Step 2:获取远程分支信息并切换到 feature/ 获取所有远程分支Step 3:创建并切换到你的新分支Step 4:开始开发新…...
MapReduce(期末速成版)
起初在B站看3分钟的速成视频,感觉很多细节没听懂。 具体例子解析(文件内容去重) 对于两个输入文件,即文件A 和文件B,请编写MapReduce 程序,对两个文件进行合并,并剔除 其中重复的内容,得到一个新的输出文件…...
鸿蒙OSUniApp 移动端直播流播放实战:打造符合鸿蒙设计风格的播放器#三方框架 #Uniapp
UniApp 移动端直播流播放实战:打造符合鸿蒙设计风格的播放器 在移动互联网时代,直播已经成为一种主流的内容形式。本文将详细介绍如何使用 UniApp 框架开发一个优雅的直播流播放器,并融入鸿蒙系统的设计理念,实现一个既美观又实用…...

C3、C2f、C3K2、C2PSA的具体结构
YOLOV5 C3 Bottleneck C2f...

2_MCU开发环境搭建-配置MDK兼容Keil4和C51
MCU开发环境搭建-配置MDK兼容Keil4和C51 一、概述 本文以MDK-ARM V5.36版本基础介绍DMK-ARM工程兼容Keil4和C51的配置。 注:在阅读本文前,请先安装和配置完成MDK-ARM(Keil5)。 二、工具包下载 链接: https://pan.baidu.com/s/1Tu2tDD6zRra4xb_PuA1Wsw 提取码: 81pp 三、…...

通过远程桌面连接Windows实例提示“出现身份验证错误,无法连接到本地安全机构”错误怎么办?
本文介绍通过远程桌面连接Windows实例提示“出现身份验证错误无法连接到本地安全机构”错误的解决方案。 问题现象 通过本地电脑内的远程桌面连接Windows实例提示“出现身份验证错误,无法连接到本地安全机构”错误。 问题原因 导致该问题的可能原因如下&#x…...

百度golang研发一面面经
输入一个网址,到显示界面,中间的过程是怎样的 IP 报文段的结构是什么 Innodb 的底层结构 知道几种设计模式 工厂模式 简单工厂模式:根据传入类型参数判断创建哪种类型对象工厂方法模式:由子类决定实例化哪个类抽象工厂模式&#…...

TC3xx学习笔记-启动过程详解(一)
文章目录 前言Firmware启动过程BMHD Check流程ABM启动Internal Flash启动Bootloader ModeProcessing in case no valid BMHD foundProcessing in case no Boot Mode configured by SSW 总结 前言 之前介绍过UCB BMHD的使用,它在启动过程中起着重要的作用࿰…...

Scratch节日 | 六一儿童节抓糖果
六一儿童节怎么能没有糖果?这款 六一儿童节抓糖果 小游戏,让你变身小猫,开启一场甜蜜大作战! 🎮 游戏玩法 帮助小猫收集所有丢失的糖果,收集越多分数越高! 小心虫子一样的“坏糖果”ÿ…...
系统调用与程序接口的关系
程序接口类型 系统调用:是操作系统提供给应用程序的接口 ,允许应用程序请求操作系统执行特定操作,像文件操作(打开、读写、关闭文件 )、进程管理(创建、终止进程 )、设备管理(操作磁…...
从线性方程组角度理解公式 s=n−r(3E−A)
从线性方程组角度理解公式 sn−r(3E−A) 这个公式本质上是 齐次线性方程组解空间维度 的直接体现。下面通过三个关键步骤解释其在线性方程组中的含义: 1. 公式对应的线性方程组 考虑矩阵方程: (3E−A)x0 其中: x 是 n 维未知向量3E−…...