1. 指派问题
1.1 问题描述
某公司准备指派 n n n个工人 X 1 , X 2 , . . . , X n X_1,X_2,...,X_n X1,X2,...,Xn做 n n n件工作 Y 1 , Y 2 , . . . , Y n Y_1,Y_2,...,Y_n Y1,Y2,...,Yn,由于每个工人完成不同工作的效率不同,公司希望在所有工作都得到完成的前提下使得效率达到最大考虑。这类指派问题也称为二部图的最小权重匹配问题(minimum weight matching in bipartite graphs)。
一个赋权的完全二部图 G = ( V 1 , V 2 , E ) G=(V_1,V_2,E) G=(V1,V2,E),其中 V 1 = ( X 1 , X 2 , . X n ) V_1=(X_1,X2,.Xn) V1=(X1,X2,.Xn), V 2 = ( Y 1 , Y 2 , . . . , Y n ) V_2=(Y_1,Y_2,...,Y_n) V2=(Y1,Y2,...,Yn),边 ( X i , Y j ) (X_i,Y_j) (Xi,Yj)上的权重 c i j c_{ij} cij表示工人 X i X_i Xi完成工作 Y j Y_j Yj的效率。指派问题显然等价于在该图中寻找有最小权重的完美匹配。
1.2 数学模型
指派问题可表述为如下0-1规划问题:
m
i
n
∑
i
=
1
n
∑
j
=
1
n
c
i
j
x
i
j
∑
i
=
1
n
x
i
j
=
1
,
i
=
1
,
2
,
.
.
.
n
∑
j
=
1
n
x
i
j
=
1
,
j
=
1
,
2
,
.
.
.
n
x
i
j
∈
{
0
,
1
}
min\sum_{i=1}^{n}\sum_{j=1}^{n}{c_{ij} x_{ij}}\\ \sum_{i=1}^{n}x_{ij} =1, \quad i=1,2,...n\\ \sum_{j=1}^{n}x_{ij} = 1, \quad j=1,2,...n\\ x_{ij}\in{\{0,1}\}
mini=1∑nj=1∑ncijxiji=1∑nxij=1,i=1,2,...nj=1∑nxij=1,j=1,2,...nxij∈{0,1}
2. Scipy求解
- scipy.optimize.linear_sum_assignment求解指派问题使用的是匈牙利算法,对于数据要求比较苛刻,成本矩阵不能太大,如果是大型矩阵需要先进行稀疏处理,否则求解效率会变低。
- Scipy官方API
scipy.optimize.linear_sum_assignment()
Solve the linear sum assignment problem.
Parameters:
cost_matrixarray
The cost matrix of the bipartite graph.
maximizebool (default: False)
Calculates a maximum weight matching if true.
Returns:
row_ind, col_indarray
An array of row indices and one of corresponding column indices giving the optimal assignment. The cost of the assignment can be computed as cost_matrix[row_ind, col_ind].sum(). The row indices will be sorted; in the case of a square cost matrix they will be equal to numpy.arange(cost_matrix.shape[0]).
- python代码示例
import numpy as np
from scipy.optimize import linear_sum_assignment
worker_num = 10 # 员工数量
job_num = 10 # 任务数量
# 随机生成成本矩阵
cost_matrix = np.random.randint(1, 10, size=(worker_num, job_num))
# 优化求解得到最佳分配下的行列索引值
row_ind, col_ind = linear_sum_assignment(cost_matrix)
# 输出结果
print('cost_matrix=\n', cost_matrix)
for i in list(zip(row_ind + 1, col_ind + 1)):
print(i[0], '->', i[1])
print('min_cost=', cost_matrix[row_ind, col_ind].sum())
- 结果