参考博客

参考博客2

参考博客3

一、背景介绍

例如有3个任务ABC,要分配给甲乙丙三人分别去完成,每个人完成3个任务所耗费精力不同(因为每个人特长不同),此处也叫完成任务耗费的代价,合理分配任务,可以达到总效率最高的目标。

例如:

甲乙丙完成ABC三个任务,花费的精力分别为:

A B C
7 2 4
1 6 5
4 3 4

此时若想达到耗费总精力最小,可以用穷举法一个个试,一共有6种组合,分别是:

1:甲A,乙B,丙C        7+6+4=17

2:甲A,乙C,丙B        7+5+3=15

3:甲B,乙A,丙C        2+1+4=7

4:甲B,乙C,丙A        2+5+4=11

5:甲C,乙A,丙B        4+1+3=8

6:甲C,乙B,丙A        4+6+4=14

所以方案3最符合需求

对于任务数和执行者数目较少时,用穷举法尚可,但是若任务数很大时,穷举数目也将以n!的形势增加,匈牙利算法的提出就是为了优化这个问题。

二、匈牙利算法

将上面所提的任务和执行人耗费精力的值,用矩阵来记录,则为一个3X3的矩阵

矩阵每行减去该行最小元素

接着矩阵每列减去该列最小元素

用最少的横线或竖线覆盖所有含0的行或列,若线数目=n则算法结束

算法步骤:

1.每行元素减去行最小

2.每列元素减去列最小

3.用虽少的横竖线覆盖0元素,若横竖线数目=n,则结束,否则执行4

4.横竖线未覆盖区域取最小值m,未覆盖的元素所在行元素-m,已覆盖的列元素+m

5.重复4直到结束

三、代码实现

import itertools
import numpy as np
from numpy import random
from scipy.optimize import linear_sum_assignment# 任务分配类
class TaskAssignment:# 类初始化,需要输入参数有任务矩阵以及分配方式,其中分配方式有两种,全排列方法all_permutation或匈牙利方法Hungary。def __init__(self, task_matrix, mode):self.task_matrix = task_matrixself.mode = modeif mode == 'all_permutation':self.min_cost, self.best_solution = self.all_permutation(task_matrix)if mode == 'Hungary':self.min_cost, self.best_solution = self.Hungary(task_matrix)# 全排列方法def all_permutation(self, task_matrix):number_of_choice = len(task_matrix)solutions = []values = []for each_solution in itertools.permutations(range(number_of_choice)):  #对0 1 2进行排列组合,每个each_solution代表一个组合each_solution = list(each_solution)solution = []value = 0for i in range(len(task_matrix)):value += task_matrix[i][each_solution[i]]  #按各种组合将最终代价加出来#print(task_matrix[i][each_solution[i]])   #00+11+22  00+12+21  01+10+22  01+12+20solution.append(task_matrix[i][each_solution[i]])values.append(value)solutions.append(solution) #每个组合的n个值min_cost = np.min(values)best_solution = solutions[values.index(min_cost)]return min_cost, best_solution# 匈牙利方法def Hungary(self, task_matrix):b = task_matrix.copy()# 行和列减0for i in range(len(b)):    #行数row_min = np.min(b[i]) #第i行最小值for j in range(len(b[i])):b[i][j] -= row_min #行每个元素减去行最小值for i in range(len(b[0])):col_min = np.min(b[:, i])#每列从0:2for j in range(len(b[:, i])):b[j][i] -= col_min #列每个元素减去列最小line_count = 0# 线数目小于矩阵长度时,进行循环while (line_count < len(b)):print('b=\n',b)line_count = 0row_zero_count = []col_zero_count = []for i in range(len(b)):#print(b[i] == 0)row_zero_count.append(np.sum(b[i] == 0))  #b[i] == 0  true false true  判断矩阵每行有几个0,然后把个数记录在row_zero_count里面print(row_zero_count)for i in range(len(b[0])):col_zero_count.append((np.sum(b[:, i] == 0))) #判断矩阵每列有几个0,然后把个数记录在col_zero_count里面#print(col_zero_count)# 划线的顺序(分行或列)line_order = []row_or_col = []for i in range(len(b[0]), 0, -1):  #此循环为了将行列的0用横竖线全覆盖,横线的row_or_col记为0,竖线的row_or_col记为1#print(i,'pppp  ')while (i in row_zero_count):line_order.append(row_zero_count.index(i))#print(i,' ',line_order,' ',row_zero_count.index(i)) #row_zero_count.index(i)含义是row_zero_count中i的序号row_or_col.append(0)#用来跳出whilerow_zero_count[row_zero_count.index(i)] = 0#print(row_zero_count)while (i in col_zero_count):line_order.append(col_zero_count.index(i))row_or_col.append(1)col_zero_count[col_zero_count.index(i)] = 0# 画线覆盖0,并得到行减最小值,列加最小值后的矩阵delete_count_of_row = []delete_count_of_rol = []row_and_col = [i for i in range(len(b))] # i=for i in range(len(b))的每个值#print(len(line_order))#print('b=\n',b,'\n')for i in range(len(line_order)):if row_or_col[i] == 0:  #如果是横线delete_count_of_row.append(line_order[i])else:  #竖线delete_count_of_rol.append(line_order[i])c = np.delete(b, delete_count_of_row, axis=0)   #axis=0 按行删除,删除第delete_count_of_row行c = np.delete(c, delete_count_of_rol, axis=1)   #按列删除print('c=\n',c,'\n')line_count = len(delete_count_of_row) + len(delete_count_of_rol)print('i=',i,' ',delete_count_of_row,' ',delete_count_of_rol)# 线数目等于矩阵长度时,跳出if line_count == len(b):break# 判断是否画线覆盖所有0,若覆盖,进行加减操作if 0 not in c:   #此处对中间矩阵b不断更新,直到最小划线数=nprint('-----------------\n')row_sub = list(set(row_and_col) - set(delete_count_of_row)) min_value = np.min(c)print(row_sub,' ',min_value)for i in row_sub:b[i] = b[i] - min_value #未被覆盖的行均减去最小值for i in delete_count_of_rol:b[:, i] = b[:, i] + min_value #被覆盖的列均加最大值break#其实此处之上的代码完全可以不用,直接使用linear_sum_assignment(task_matrix)就是最终解,上方代码可以作为匈牙利算法执行逻辑的展现row_ind, col_ind = linear_sum_assignment(b)     #线性和分配问题   匈牙利算法函数包,直接输入task_matrix即可返回每行对应最小的列, 0 1 2,0 2 1print(row_ind,' ',col_ind)min_cost = task_matrix[row_ind, col_ind].sum()  #012 120   01 12 20best_solution = list(task_matrix[row_ind, col_ind])return min_cost, best_solution# 这个叫随机种子数,它一旦固定,则后续结果都是可以复现的。
rd = random.RandomState(1000)
task_matrix = rd.randint(0, 100, size=(4, 4))
# 用全排列方法实现任务分配
ass_by_per = TaskAssignment(task_matrix, 'all_permutation')
# 用匈牙利方法实现任务分配
ass_by_Hun = TaskAssignment(task_matrix, 'Hungary')print('cost matrix = ', '\n', task_matrix)print('匈牙利方法任务分配:')
print('min cost = ', ass_by_Hun.min_cost)
print('best solution = ', ass_by_Hun.best_solution)print('全排列方法任务分配:')
print('min cost = ', ass_by_per.min_cost)
print('best solution = ', ass_by_per.best_solution)
print('\n',linear_sum_assignment(task_matrix))

简单版:

import numpy as np
from numpy import random
from scipy.optimize import linear_sum_assignment# 这个叫随机种子数,它一旦固定,则后续结果都是可以复现的。
rd = random.RandomState(1000)
task_matrix = rd.randint(0, 100, size=(4, 4))
print('task_matrix =\n',task_matrix)
row_ind, col_ind = linear_sum_assignment(task_matrix)     #线性和分配问题   匈牙利算法函数包,直接输入task_matrix即可返回每行对应最小的列
min_cost = task_matrix[row_ind, col_ind].sum()
best_solution = list(task_matrix[row_ind, col_ind])
print('min_cost =',min_cost)
print('best_solution =',best_solution)

匈牙利算法--任务分配相关推荐

  1. java蛮力法解决任务分配问题_【算法题】任务分配问题---匈牙利算法

    一.问题描述 问题描述:N个人分配N项任务,一个人只能分配一项任务,一项任务只能分配给一个人,将一项任务分配给一个人是需要支付报酬,如何分配任务,保证支付的报酬总数最小. 问题数学描述: 二.实例分析 ...

  2. 匈牙利算法的基本原理与Python实现

    一.问题描述 问题描述:N个人分配N项任务,一个人只能分配一项任务,一项任务只能分配给一个人,将一项任务分配给一个人是需要支付报酬,如何分配任务,保证支付的报酬总数最小. 问题数学描述: 二.实例分析 ...

  3. 匈牙利算法Hungarian algorithm

    匈牙利算法是解决寻找二分图最大匹配的. 匈牙利算法(Hungarian Algorithm)是一种组合优化算法(combinatorial optimization algorithm),换句话说就是 ...

  4. 二分图匹配匈牙利算法DFS实现

    1 /*==================================================*\ 2 | 二分图匹配(匈牙利算法DFS 实现) 3 | INIT: g[][]邻接矩阵; ...

  5. 解题报告:luogu P2423 [HEOI2012]朋友圈【最大团转最大点独立集(匈牙利算法+时间戳优化)】

    图的最大团:"任意两点之间都有一条边相连"的子图被称为无向图的团,点数最多的团为图的最大团 朋友圈中任意两个点之间都有关系,既是图中的团. 答案就是图中的最大团. 我们如果把B国的 ...

  6. 二分图最大匹配(匈牙利算法) POJ 3020 Antenna Placement

    题目传送门 1 /* 2 题意:*的点占据后能顺带占据四个方向的一个*,问最少要占据多少个 3 匈牙利算法:按坐标奇偶性把*分为两个集合,那么除了匹配的其中一方是顺带占据外,其他都要占据 4 */ 5 ...

  7. 二分图匹配的匈牙利算法

    匈牙利算法,很绕,其实写起来也就一点点长度.. bool find(int a){int i,j;for(i=head[a];i;i=next[i]){j=to[i];//获得相邻的点if(!unab ...

  8. 二分图-匈牙利算法模板

    二分图就不赘述了,我在知识资料整理有相关资料. .最大匹配  .最小路径覆盖  .最小点覆盖  .最大独立集 最大匹配:二分图中边集最大的那个匹配 最小路径(边)覆盖:用尽量小的不想交简单路径覆盖有向 ...

  9. 二分图的最大匹配—匈牙利算法

    [基本概念]: 二分图: 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分 ...

  10. BZOJ 1433 Luogu P2055 [ZJOI2009]假期的宿舍 匈牙利算法

    刚学了匈牙利正好练练手(我不会说一开始我写错了)(怕不是寒假就讲了可是我不会) 把人看做左部点,床看作右部点 建图:(!!在校相当于有床,不在校相当于没有床 但是要来学校) 1.在校的 不走的人 自己 ...

最新文章

  1. VirtualBox 下USB 设备加载的步骤及无法加载的解决办法
  2. activiti 工作流_技术干货 | 金仓通用数据库中,如何使用Activiti快速开发工作流应用?...
  3. 2018.8.18 servlet使用的会话跟踪除session外还有哪些方式
  4. UpTime:供电、系统、网络、制冷——2020年数据中心宕机四大主因
  5. Selenium常用的8大元素定位方法
  6. 不同级别成员对应三种继承的结果:
  7. html读取oss_阿里云使用js 实现OSS图片上传、获取OSS图片列表(示例代码)
  8. Oracle 11g中关于数据定义的思考
  9. 双机高可用、负载均衡、MySQL(读写分离、主从自动切换)架构设计
  10. stackoverflowerror解决办法
  11. 关于给构造函数传达参数方法
  12. php json schema,json-schema-php
  13. 印象笔记html预览,超级笔记使用指南 | 印象笔记
  14. mcisendString制作播放器
  15. 浅析密码测评的重要性(附密码产品和功能测评技术实施方法)
  16. 一个写着玩的 bitcoin 客户端
  17. 《关于雪糕刺客与雪糕护卫激发中国人的创作灵感这件事》
  18. 我真的不懂微信营销(一)
  19. 仿古砖搭配这样做,会有不同的效果
  20. 永磁同步电机转子位置估算专题 —— 基波模型类位置估算概要

热门文章

  1. 【Matlab应用】:相控阵天线方向图合成及波束扫描算法实现
  2. 什么是私域?什么是会员制?
  3. 大学生搜题软件哪个好用?2020搜题软件排行榜
  4. java如何统计txt的字数_Java HashSet对txt文本内容去重(统计小说用过的字或字数)...
  5. ENVI5.3.1使用Landsat 8影像进行监督分类实例操作
  6. 160813_qt显示阿拉伯输入法9x7点阵
  7. c++小学生信息学奥赛变量练习(魔方)
  8. VSTOhowtoreferene.Net3.5(VSTO如何引用.NET3.5的外接程序)
  9. 苹果迅雷iOS版安装教程
  10. python解决八数码问题_A*算法实践——八数码问题