匈牙利匹配算法_学习笔记_Python编程实现

2023-11-10

大家好,下面是我关于匈牙利匹配算法的学习记录,内含两个例题的Python编程实现。这是我的第一篇博客,参考的网站在文中都有标注,如有问题欢迎指出~

匈牙利算法1——无权重二部图最大匹配

用于解决无权重二部图最大匹配问题,一个经典的解决无权重二分图的最大匹配问题的算法。
应用:机器人路径规划,群体智能(group intelligence)

几个概念

  1. 匹配:节点之间的连接关系;
  2. 二分图:节点被分为两类的图,不同类之间能够相互匹配,同类之间不能匹配,且每个节点最多仅能与一个其他节点匹配;
  3. 最大匹配:二分图所有匹配可能性中,匹配对数最多的情况;
  4. 完美匹配:所有节点都得到匹配(完美匹配一定是最大匹配);
  5. 交替路:未匹配边->匹配边->未匹配边……交替的路;
  6. 增广路:是一个交替路,且非匹配边比匹配边多一条;
  7. 交替树:选一个空闲节点(树根)出发,遍历所有可能的交替路,构成交替树。

算法核心思想

如果把增广路中的匹配边和非匹配边相互调换,匹配边就比原来多一条。

算法理论依据

Berge’s Theorem: A matching M is maximun if it has no augmenting path.
Berge 定理:如果匹配 M 没有增广路径,则它是最大的(匹配)。

来自论文《The Hungarian Method 》1955,Naval Research Logistic Quarterly

算法伪代码

Given a bipartite graph G = ((X U Y),E)
for every v in x
{
	if v is free
	{
		Find an augmenting path p start from v
		if p is not empty
			switch the edges in the path
	}
}

解释说明:
以上算法可以用下图举例说明:
在这里插入图片描述
不断重复以上Step2和Step3:
在这里插入图片描述
在这里插入图片描述

算法复杂度

找节点v出发的增广路(可用广度优先BFS或深度优先DFS)复杂度:O(E)
外层循环V次
总复杂度:VO(E)

算法练习题1

要求:用匈牙利算法1实现求解下图的最大匹配的过程
在这里插入图片描述

上图可转化为如下二部图:
等价二部图
手动算法实现:
绿色表示未匹配边与节点,橙色表示匹配边与节点
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Python算法实现

参考链接: https://blog.csdn.net/ying86615791/article/details/117735977

Python源程序:

# N和M分别代表左右边节点的个数,
# edges代表节点之间的连线:(右边节点,左边节点)
# graph是N*M矩阵, 记录左右节点之间是否存在连线
N = 4
M = 4
edges = [(0,0), (0,1), (0,2), (1,2), (2,0), (2,3),  (3,3)]
graph = []
for i in range(N):
    graph.append([])
    for j in range(M):
        if (i, j) in edges:
            graph[i].append(1)
        else:
            graph[i].append(0)
# print("初始图: ")
# for i in range(N):
#     print(graph[i])
# print("")
 
def find(x, graph, match, used):

    # x (int): 当前尝试配对的左节点索引
    # graph (list[list]): [N[M]], 是N*M矩阵, 记录左右节点之间是否存在连线
    # match (list[int]): [M], 记录右节点被分配给坐标哪个节点
    # used (list[int]): [M], 记录在本轮配对中某个右节点是否已经被访问过,
    # 因为每一轮每个右节点只能被访问一次, 否则会被重复配对

    for j in range(M):
        # x和j是存在连线 and (j在本轮还没被访问过)
        if graph[x][j] == 1 and not used[j]:
            used[j] = True
            # j还没被分配 or 成功把j腾出来(通过递归, 给j之前分配的左节点成功分配了另外1个右节点)
            if match[j] == -1 or find(match[j], graph, match, used):
                match[j] = x
                return True
    return False
 
# match记录左边节点最终与左边哪个节点匹配
match = [-1 for _ in range(M)]
# count记录最终的匹配数
count = 0
# # 遍历左节点, 依次尝试配对左边每个节点,
# 对于每次尝试配对的左节点, 
# 如果能在右边找到与之匹配的右节点
# 则匹配数+1
for i in range(N):
    # 每一轮是一次全新的查找, 所以used要重置,
    # 但是是基于前面几轮找到的最优匹配, 所以match是复用的
    used = [False for _ in range(M)]
    if find(i, graph, match, used):
        count += 1
#将节点序号转化为节点编号
num = []
for i in range(M):
    num.append([])
    if match[i] == 0:
        num[i] = 5
    elif match[i] == 1:
        num[i] = 6 
    elif match[i] == 2:
        num[i] = 7
    elif match[i] == 3:
        num[i] =8
    else:
        num[i]=-1

print("最大匹配个数: ", count)
print("左节点匹配到的右节点序号: ", num)

输出结果为:
在这里插入图片描述
与推导结果一致。

匈牙利算法2——有权值二部图最小权值匹配

解决有权值二部图最小权值匹配问题的算法。
应用:运动对象轨迹追踪(把视频分成帧,不同帧之间根据相似度对像素加权,跟踪同一个物体)

算法依据

定理1:如果在成本矩阵的任何一行或一列的所有条目上加或减一个数,则所得的成本矩阵的最优分配也是原始成本矩阵的最优分配。

定理2:当一个非负矩阵有代价为零的分配,则该分配就是一个最佳分配。

算法思路

通过对行和列的加减运算,将原矩阵变换为一个非负矩阵,方便找到最佳分配。

问题举例

  • 已知
    (1)完成一项工作需要4道工序;
    (2)有5个工人(w1-w5),每人完成每道工序需要的时间不同

  • 选择哪四个人,以及分配哪个人干哪个工序,才能使完成工作所需总时间最短?
    在这里插入图片描述

算法流程

  • step1:转化为方阵,少的行/列用最大值填充;

  • step2:找出每行最小元素值,每行所有元素分别减去本行最小值;

  • step3:找出所有列中最小元素,每列减去本列最小值;

  • step4:用最少的直线覆盖矩阵中的全部0元素。如果直线数量等于矩阵行数(秩),则调到step6,否则,从没被线划过的元素中找到最小值x,然后矩阵中每次被线划过都增加x(划过n次则+nx),如下图所示;
    在这里插入图片描述
    此操作仍满足定理1

  • step5:从矩阵全部元素中找最小值n,所有元素均减去n,如下图所示:
    在这里插入图片描述

  • 重复step4和step5,知道满足结束条件,调到step6

  • step6:最终,选出M个0,每个0在不同行不同列
    在这里插入图片描述

整体流程总结如下:
在这里插入图片描述

算法练习题2

广告平台在不同时间段投放不同广告的收益不同,如下表。如果每个广告只能选择一个时间段,一个时间段只能播一个广告,怎么匹配广告和时间段才能最大化广告平台的收益?
在这里插入图片描述

上表的值用最大值19减去每一个值,可以将问题转化为有权值二部图最小权值匹配问题,转化后表格如下:
在这里插入图片描述
利用匈牙利算法2的流程分析如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Python算法实现

参考链接:https://blog.csdn.net/tommy0095/article/details/104466364

Python源代码如下:

import numpy as np
import collections
import time

class Hungarian():
    
    def __init__(self, input_matrix=None, is_profit_matrix=False):
        # is_profit_matrix=False代表输入是消费矩阵(需要使消费最小化),反之则为利益矩阵(需要使利益最大化)

        if input_matrix is not None:
            # 保存输入
            my_matrix = np.array(input_matrix)
            self._input_matrix = np.array(input_matrix)
            self._maxColumn = my_matrix.shape[1]
            self._maxRow = my_matrix.shape[0]

            # 如果需要,则转化为消费矩阵
            if is_profit_matrix:
                my_matrix = self.make_cost_matrix(my_matrix)

            self._cost_matrix = my_matrix
            self._size = len(my_matrix)
            self._shape = my_matrix.shape

            # 存放算法结果
            self._results = []
            self._totalPotential = 0
        else:
            self._cost_matrix = None
    def make_cost_matrix(self,profit_matrix):
        # 利益矩阵转化为消费矩阵,输出为numpy矩阵
        # 消费矩阵 = 利益矩阵最大值组成的矩阵 - 利益矩阵
        matrix_shape = profit_matrix.shape
        offset_matrix = np.ones(matrix_shape, dtype=int) * profit_matrix.max()
        cost_matrix = offset_matrix - profit_matrix
        return cost_matrix
    def get_results(self):
        # 获取算法结果
        return self._results
    def calculate(self):
        # 实施匈牙利算法的函数
        result_matrix = self._cost_matrix.copy()

        # Step1: 矩阵每一行减去本行的最小值
        for index, row in enumerate(result_matrix):
            result_matrix[index] -= row.min()

        # Step2: 矩阵每一列减去本行的最小值
        for index, column in enumerate(result_matrix.T):
            result_matrix[:, index] -= column.min()

        # Step3: 使用最少数量的划线覆盖矩阵中所有的0元素
        # 如果划线总数不等于矩阵的维度需要进行矩阵调整并重复循环此步骤
        total_covered = 0
        while total_covered < self._size:
           
            # 使用最少数量的划线覆盖矩阵中所有的0元素同时记录划线数量
            cover_zeros = CoverZeros(result_matrix)
            single_zero_pos_list = cover_zeros.calculate()
            covered_rows = cover_zeros.get_covered_rows()
            covered_columns = cover_zeros.get_covered_columns()
            total_covered = len(covered_rows) + len(covered_columns)

            # 如果划线总数不等于矩阵的维度需要进行矩阵调整(需要使用未覆盖处的最小元素)
            if total_covered < self._size:
                result_matrix = self._adjust_matrix_by_min_uncovered_num(result_matrix, covered_rows, covered_columns)
        #元组形式结果对存放到列表
        self._results = single_zero_pos_list
        # 计算总期望结果
        value = 0
        for row, column in single_zero_pos_list:
            value += self._input_matrix[row, column]
        self._totalPotential = value

    def get_total_potential(self):
        return self._totalPotential

    def _adjust_matrix_by_min_uncovered_num(self, result_matrix, covered_rows, covered_columns):
        # 计算未被覆盖元素中的最小值(m),未被覆盖元素减去最小值m,行列划线交叉处加上最小值m
        adjusted_matrix = result_matrix
        # 计算未被覆盖元素中的最小值(m)
        elements = []
        for row_index, row in enumerate(result_matrix):
            if row_index not in covered_rows:
                for index, element in enumerate(row):
                    if index not in covered_columns:
                        elements.append(element)
        min_uncovered_num = min(elements)
        #未被覆盖元素减去最小值m
        for row_index, row in enumerate(result_matrix):
            if row_index not in covered_rows:
                for index, element in enumerate(row):
                    if index not in covered_columns:
                        adjusted_matrix[row_index,index] -= min_uncovered_num
        #print('未被覆盖元素减去最小值m',adjusted_matrix)
    
        #行列划线交叉处加上最小值m
        for row_ in covered_rows:
            for col_ in covered_columns:
                adjusted_matrix[row_,col_] += min_uncovered_num
        #print('行列划线交叉处加上最小值m',adjusted_matrix)

        return adjusted_matrix



class CoverZeros():
    # 使用最少数量的划线覆盖矩阵中的所有零
    # 输入为numpy方阵
    def __init__(self, matrix):
        # 找到矩阵中零的位置(输出为同维度二值矩阵,0位置为true,非0位置为false)
        self._zero_locations = (matrix == 0)
        self._zero_locations_copy = self._zero_locations.copy()
        self._shape = matrix.shape

        # 存储划线盖住的行和列
        self._covered_rows = []
        self._covered_columns = []

    def get_covered_rows(self):
        # 返回覆盖行索引列表
        return self._covered_rows

    def get_covered_columns(self):
        # 返回覆盖列索引列表
        return self._covered_columns

    def row_scan(self,marked_zeros):
        # 扫描矩阵每一行,找到含0元素最少的行,对任意0元素标记(独立零元素),划去标记0元素(独立零元素)所在行和列存在的0元素
        min_row_zero_nums = [9999999,-1]
        for index, row in enumerate(self._zero_locations_copy):#index为行号
            row_zero_nums = collections.Counter(row)[True]
            if row_zero_nums < min_row_zero_nums[0] and row_zero_nums!=0:
                #找最少0元素的行
                min_row_zero_nums = [row_zero_nums,index]
        #最少0元素的行
        row_min = self._zero_locations_copy[min_row_zero_nums[1],:]
        #找到此行中任意一个0元素的索引位置即可
        row_indices, = np.where(row_min)
        #标记该0元素
        marked_zeros.append((min_row_zero_nums[1],row_indices[0]))
        #划去该0元素所在行和列存在的0元素
        #因为被覆盖,所以把二值矩阵_zero_locations中相应的行列全部置为false
        self._zero_locations_copy[:,row_indices[0]] = np.array([False for _ in range(self._shape[0])])
        self._zero_locations_copy[min_row_zero_nums[1],:] = np.array([False for _ in range(self._shape[0])])

    def calculate(self):
        # 进行计算
        #储存勾选的行和列
        ticked_row   = []
        ticked_col   = []
        marked_zeros = []
        #1、试指派并标记独立零元素
        while True:
            #print('_zero_locations_copy',self._zero_locations_copy)
            #循环直到所有零元素被处理(_zero_locations中没有true)
            if True not in self._zero_locations_copy:
                break
            self.row_scan(marked_zeros)
            
        #2、无被标记0(独立零元素)的行打勾
        independent_zero_row_list = [pos[0] for pos in marked_zeros]
        ticked_row = list(set(range(self._shape[0])) - set(independent_zero_row_list))
        #重复3,4直到不能再打勾
        TICK_FLAG = True
        while TICK_FLAG:
            #print('ticked_row:',ticked_row,'   ticked_col:',ticked_col)
            TICK_FLAG = False
            #3、对打勾的行中所含0元素的列打勾
            for row in ticked_row:
                #找到此行
                row_array = self._zero_locations[row,:]
                #找到此行中0元素的索引位置
                for i in range(len(row_array)):
                    if row_array[i] == True and i not in ticked_col:
                        ticked_col.append(i)
                        TICK_FLAG = True
            
            #4、对打勾的列中所含独立0元素的行打勾
            for row,col in marked_zeros:
                if col in ticked_col and row not in ticked_row:
                    ticked_row.append(row)
                    FLAG = True
        #对打勾的列和没有打勾的行画画线
        self._covered_rows    = list(set(range(self._shape[0])) - set(ticked_row))
        self._covered_columns = ticked_col

        return marked_zeros

if __name__ == '__main__':
    cost_matrix = [
        [9, 0, 8, 4],
        [9, 1, 11, 2],
        [6, 3, 9, 5],
        [7, 0, 6, 1]]
    hungarian = Hungarian(cost_matrix)
    hungarian.calculate()
    print("Calculated value:\t", hungarian.get_total_potential()) 
    print("Results:\n\t", hungarian.get_results())
    print("-" * 80)

    profit_matrix = [
        [10, 19, 11, 15],
        [10, 18, 8, 17],
        [13, 16, 10, 14],
        [12, 19, 13, 18]]

    hungarian = Hungarian(profit_matrix, is_profit_matrix=True)
    hungarian.calculate()
    print("Calculated value:\t", hungarian.get_total_potential()) 
    print("Results:\n\t", hungarian.get_results())

输出结果为:
在这里插入图片描述
其中,第一个输出是将利益矩阵转化为成本矩阵后(转化方式如前所述),完全按照匈牙利算法求解的结果,最大利益应为19*4-14=62;
第二个输出是通过关系式“消费矩阵 = 利益矩阵最大值组成的矩阵 - 利益矩阵”转化,求解结果即为最大利益;
两个输出的匹配方式均与按算法流程推导的结果一致。

以上,如有问题欢迎指出~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

匈牙利匹配算法_学习笔记_Python编程实现 的相关文章

  • Python:在列表理解本身中引用列表理解?

    这个想法刚刚出现在我的脑海中 假设您出于某种原因想要通过 Python 中的列表理解来获取列表的唯一元素 i if i in created comprehension else 0 for i in 1 2 1 2 3 1 2 0 0 3
  • 无法“安装”plpython3u - postgresql

    我正在尝试在 postgresql 中使用 python 语言 像这样的事情 create or replace function test a integer returns integer as if a 2 0 return even
  • OpenCV Python cv2.mixChannels()

    我试图将其从 C 转换为 Python 但它给出了不同的色调结果 In C Transform it to HSV cvtColor src hsv CV BGR2HSV Use only the Hue value hue create
  • Python(Selenium):如何通过登录重定向/组织登录登录网站

    我不是专业程序员 所以请原谅任何愚蠢的错误 我正在做一些研究 我正在尝试使用 Selenium 登录数据库来搜索大约 1000 个术语 我有两个问题 1 重定向到组织登录页面后如何使用 Selenium 登录 2 如何检索数据库 在我解决
  • Python - StatsModels、OLS 置信区间

    在 Statsmodels 中 我可以使用以下方法拟合我的模型 import statsmodels api as sm X np array 22000 13400 47600 7400 12000 32000 28000 31000 6
  • SQLALchemy .query:类“Car”的未解析属性引用“query”

    我有一个这里已经提到的问题https youtrack jetbrains com issue PY 44557 https youtrack jetbrains com issue PY 44557 但我还没有找到解决方案 我使用 Pyt
  • Python 函数可以从作用域之外赋予新属性吗?

    我不知道你可以这样做 def tom print tom s locals locals def dick z print z name z name z guest Harry print z guest z guest print di
  • 如何使用 OpencV 从 Firebase 读取图像?

    有没有使用 OpenCV 从 Firebase 读取图像的想法 或者我必须先下载图片 然后从本地文件夹执行 cv imread 功能 有什么办法我可以使用cv imread link of picture from firebase 您可以
  • 绘制方程

    我正在尝试创建一个函数 它将绘制我告诉它的任何公式 import numpy as np import matplotlib pyplot as plt def graph formula x range x np array x rang
  • 如何在ipywidget按钮中显示全文?

    我正在创建一个ipywidget带有一些文本的按钮 但按钮中未显示全文 我使用的代码如下 import ipywidgets as widgets from IPython display import display button wid
  • Flask如何获取请求的HTTP_ORIGIN

    我想用我自己设置的 Access Control Allow Origin 标头做出响应 而弄清楚请求中的 HTTP ORIGIN 参数在哪里似乎很混乱 我在用着烧瓶 0 10 1 以及HTTP ORIGIN似乎是这个的特点之一object
  • 如何使用Python创建历史时间线

    So I ve seen a few answers on here that helped a bit but my dataset is larger than the ones that have been answered prev
  • 在f字符串中转义字符[重复]

    这个问题在这里已经有答案了 我遇到了以下问题f string gt gt gt a hello how to print hello gt gt gt f a a gt gt gt f a File
  • python获取上传/下载速度

    我想在我的计算机上监控上传和下载速度 一个名为 conky 的程序已经在 conky conf 中执行了以下操作 Connection quality alignr wireless link qual perc wlan0 downspe
  • Pandas:merge_asof() 对多行求和/不重复

    我正在处理两个数据集 每个数据集具有不同的关联日期 我想合并它们 但因为日期不完全匹配 我相信merge asof 是最好的方法 然而 有两件事发生merge asof 不理想的 数字重复 数字丢失 以下代码是一个示例 df a pd Da
  • 向 Altair 图表添加背景实心填充

    I like Altair a lot for making graphs in Python As a tribute I wanted to regenerate the Economist graph s in Mistakes we
  • 如何在 Python 中追加到 JSON 文件?

    我有一个 JSON 文件 其中包含 67790 1 kwh 319 4 现在我创建一个字典a dict我需要将其附加到 JSON 文件中 我尝试了这段代码 with open DATA FILENAME a as f json obj js
  • Conda SafetyError:文件大小不正确

    使用创建 Conda 环境时conda create n env name python 3 6 我收到以下警告 Preparing transaction done Verifying transaction SafetyError Th
  • Python 类继承 - 诡异的动作

    我观察到类继承有一个奇怪的效果 对于我正在处理的项目 我正在创建一个类来充当另一个模块的类的包装器 我正在使用第 3 方 aeidon 模块 用于操作字幕文件 但问题可能不太具体 以下是您通常如何使用该模块 project aeidon P
  • 如何使用 Pycharm 安装 tkinter? [复制]

    这个问题在这里已经有答案了 I used sudo apt get install python3 6 tk而且效果很好 如果我在终端中打开 python Tkinter 就可以工作 但我无法将其安装在我的 Pycharm 项目上 pip

随机推荐

  • Redis主从复制的原理

    更多内容 欢迎关注微信公众号 全菜工程师小辉 公众号回复关键词 领取免费学习资料 在Redis集群中 让若干个Redis服务器去复制另一个Redis服务器 我们定义被复制的服务器为主服务器 master 而对主服务器进行复制的服务器则被称为
  • pyautogui库的使用教程(超详细)

    一 前言 PyAutoGUI 让您的 Python 脚本控制鼠标和键盘以自动与其他应用程序交互 官方文档 PyAutoGUI documentation 常用函数列表 函数名 功能 基本 pyautogui size 返回包含分辨率的元组
  • 在编辑操作时,el-select多选下拉组件,选中label标签后,框中无法回显选中的label,,,

    1 问题描述 在编辑操作时 页面的el select多选下拉组件 在选择新的label标签时 change事件和监听数组对象都能确定数据已发生改变 ngmodel绑定就是最新的id集合 但就是框中不显示最新选中的label 而change事
  • 论文导读

    图的最大独立集问题 MIS problem 是图论研究中的一个重要问题 具有广泛的应用 本文介绍了最大独立集求解相关的三篇工作 包括一篇启发式方法和两篇基于学习的方法 希望能让大家对这个问题有所了解 问题定义 一个图G V E 的顶点集子集
  • 放弃手写代码吧!用低代码你能生成各种源码

    很多同学不知道为什么要用Low code做开发 传统IT开发不行么 当然可以 传统IT自研软件开发 通过编程去写代码 还有数据库 API 第三方基础架构等 这个方式很好 但不可避免的会带来开发周期长 难度大 技术人员不易开发维护 因此价格及
  • EDUCODER---WEB__JavaScript学习手册十:正则表达式

    第一关 字符串字面量 请在此处编写代码 Begin var pattern js n End 第二关 字符类 请在此处编写代码 Begin var pattern1 a zA Z 0 9 var pattern2 A 0 9 End 第三关
  • Linux下Python环境安装与部署

    因为我是Python零基础 所以如何部署全靠百度 这边我把我查到的资料和安装使用过程中遇到写下来 如果有写的不对的或者有更好的方式 欢迎评论指出 一 Python环境安装 网上有很多安装教程 可以自行百度安装 我参考的是这个 仅第一步安装p
  • The Lost House【树形DP+期望+构造路径】

    题目链接 POJ 2057 题意 有一棵N的点的树 开始的时候蜗牛在1号结点 它不知道它的家在哪个叶子结点 树上的有些结点有虫虫 虫虫会告诉你 你的家是否在以它所在结点为根的子树上 现在需要你规划走的方案 使得找到哪个叶子结点才是家的所走路
  • python将word表格转写入excel

    Notes 想将一份 word 文件中的几个表格转写入 excel 文件中 后续用 excel 处理 用到 python docx 和 pandas 分别处理 word 和 excel 安装 python docx pip install
  • pytorch中网络loss传播和参数更新理解

    相比于2018年 在ICLR2019提交论文中 提及不同框架的论文数量发生了极大变化 网友发现 提及tensorflow的论文数量从2018年的228篇略微提升到了266篇 keras从42提升到56 但是pytorch的数量从87篇提升到
  • 利用R包ggmap进行空间可视化

    ggmap 是在R环境里调用地图作用可视化的利器 它的语法结构跟ggplot2非常相似 也使R语言的用户可以迅速上手 ggmap 结合 ggplot 可以方便快速绘制基于地图的可视化图表 下面的文章里 我将用两个例子 三藩市的犯罪记录 和
  • require 方法详解

    在 NodeJS 中有一个方法是我们使用频率最高的 那就是 require 方法 NodeJs 遵循 CommonJS 规范 该规范的核心是通过 require来加载其他依赖的模块 几个问题 module exports 或者 export
  • 朴素贝叶斯算法python sklearn实现_朴素贝叶斯算法——实现新闻分类(Sklearn实现)...

    1 朴素贝叶斯实现新闻分类的步骤 1 提供文本文件 即 2 准备数据 将数据集划分为训练集和测试集 使用jieba模块进行分词 词频统计 停用词过滤 文本特征提取 将文本数据向量化 3 分析数据 使用matplotlib模块分析 4 训练算
  • 76. 如何理解 Python 中字符串中的\字符?

    Python字符串中的 字符代表转义字符 路径名中用来连接路径名 编写太长代码手动软换行 转义符 转义符 描述 续行符 在行尾时 反斜杠符号 单引号 双引号 a 响铃 b 退格 Backspace e 转义 000 空 n 换行 v 纵向制
  • border-sizing之border-box、content-box

    border sizing是CSS3的属性之一 其属性值为border box content box 我们正常理解的盒模型其实是border sizing的属性值是content box 即正常盒模型 属性值为border box的盒模型
  • linux IO Block layer 解析

    早期的 Block 框架是单队列 single queue 架构 适用于 硬件单队列 的存储设备 比如机械磁盘 随着存储器件技术的发展 支持 硬件多队列 的存储器件越来越常见 比如 NVMe SSD 传统的单队列架构也因此被改成了多队列 m
  • IDEA插件开发

    文章目录 写在前面 1 使用IDEA新建插件项目 1 1 配置SDK并新建项目 非gradle项目 1 2 项目目录结构 1 3 plugin xml 1 4 AnAction 1 5 测试运行 1 6 打包 安装插件 2 AnAction
  • 前缀和【一维前缀和与二维前缀和】

    全文目录 一维前缀和 构建一维前缀和数组 子序列的和 二维前缀和 构建二维前缀和数组 子矩阵的和 一维前缀和 一维前缀和很简单 就是高中数学中的前n项和 设有一个数组a a a 1 a 2 a 3 a 4 a 5 a 6 a n 还有一个数
  • C++ 之指针

    文章目录 参考 描述 指针 运算符 地址运算符 奇偶分体 指针的创建 间接寻址运算符 句点运算符 运算符优先级问题 箭头运算符 运算符优先级 指针 野指针 空指针 通用指针 解引用 分析 指针的算术运算 加减运算 自增运算与自减运算 比较运
  • 匈牙利匹配算法_学习笔记_Python编程实现

    大家好 下面是我关于匈牙利匹配算法的学习记录 内含两个例题的Python编程实现 这是我的第一篇博客 参考的网站在文中都有标注 如有问题欢迎指出 匈牙利匹配算法 匈牙利算法1 无权重二部图最大匹配 几个概念 算法核心思想 算法理论依据 算法