1、问题描述
问题描述:N个人分配N项任务,一个人只能分配一项任务,一项任务只能分配给一个人,将一项任务分配给一个人是需要支付报酬,如何分配任务,保证支付的报酬总数最小。
2、算法步骤:
3、具体算法分析—匈牙利算法
Step1.
Step2
Step3.
Step4.
Step5.
4、python代码
#矩阵输入
def input_s():
a1=int(input("输入方阵边长:"))
n=0 #循环计数器,确定何时跳出循环
while 1:
b=input("矩阵第{}行:".format(n+1))
b1=list(map(eval,b.split(","))) #将字符串改为数值列表
#检查每一行输入的数是否一样多,即是否为方阵
if a1!=len(b1):
print("输入错误")
b2,a1=input_s()
break
#numpy.vstack将输入每一行合成矩阵
if n==0:
b2=b1
else:
b2=np.vstack((b2,b1))
n+=1
if n==len(b1):
break
return b2,a1
#第一步,每行每列减去最小数
def step1():
min_0=[] #存储每行每列最小数的列表
#每行减去最小数
for i in range(n):
for j in range(n):
if j==0:
min_0.append(b[i,j])
else:
if min_0[i]>b[i,j]:
min_0[i]=b[i,j]
b1[i]=b[i]-min_0[i]
#再每列减去最小数
for i in range(n):
for j in range(n):
if j==0:
min_0[i]=b1[j,i]
else:
if min_0[i]>b1[j,i]:
min_0[i]=b1[j,i]
b1[:,i]=b1[:,i]-min_0[i]
#进入下一步
step3(b1)
#第3步,直线覆盖
def step3(b1):
b2=np.zeros((n,n))
b3=b2.copy()
m=0
for i in range(n):
a=0
a1=0
for j in range(n):
if b1[i,j]==0 and b2[i,j]==0:
a+=1
a1=j
if a==1:
b2[:,a1]+=1
m+=1
b3[i,a1]+=1
for i in range(n):
a=0
a1=0
for j in range(n):
if b1[j,i]==0 and b2[j,i]==0:
a+=1
a1=j
if a==1:
b2[a1]+=1
m+=1
b3[a1,i]+=1
#有未被直线覆盖的0,但是0之间形成回路
a2=1
for i in range(n):
for j in range(n):
if b2[i,j]==0 and b1[i,j]==0:
if a2%2==0:
continue
b3[i,j]+=1
b2[i]+=1
a2+=1
m+=1
#画线数目等于方阵边数,已经找到最优解
if m==n:
zuiyoujie(b3)
elif m<n:
step4(b2)
else:
print("程序错误!")
exit()
def zuiyoujie(b3):
Z=0
for i in range(n):
for j in range(n):
if b3[i,j]==1:
Z=Z+b[i,j]
a=(i+1,j+1)
print("原矩阵位置:{}".format(a),end='')
print("最优解为Z={}".format(Z))
def step4(b2):
min_1=0
for i in range(n):
for j in range(n):
if min_1==0 and b2[i,j]==0 :
min_1=b1[i,j]
elif b2[i,j]==0 and min_1>b1[i,j]:
min_1=b1[i,j]
for i in range(n):
for j in range(n):
if b2[i,j]==0:
b1[i,j]=b1[i,j]-min_1
elif b2[i,j]==2:
b1[i,j]+=min_1
step3(b1)
import numpy as np
print("请输入矩阵,一次性输入一行,逗号分隔:")
b,n=input_s()
b1=b.copy()
step1()