python123.io能不能补交作业_作业分配问题-回溯法-Python3

题目要求:

有n份作业分配给n个人去完成,每人完成一份作业。假定第i个人完成第j份作业需要花费cij时间, cij>0,1≦i,j≦n。试设计一个回溯算法,将n份作业分配给n个人完成,使得总花费时间最短。

题目分析:

由于每个人都必须分配到工作,在这里可以建一个二维数组C[k][i],用以表示k号工人完成i号工作所需的费用。给定一个循环,从第1个工人开始循环分配工作,直到所有工人都分配到。为第k个工人分配工作时,再循环检查每个工作是否已被分配,没有则分配给k号工人,否则检查下一个工作。可以用一个二维数组t[k][j]来表示第i号工作是否被k号人分配,未分配则x[k][i]=0,否则x[k][i]=1。利用回溯思想,在工人循环结束后回到上一工人,取消此次分配的工作,而去分配下一工作直到可以分配为止。这样,一直回溯到第1个工人后,就能得到所有的可行解。在检查工作分配时,其实就是判断取得可行解时的二维数组的一下标都不相同,二下标同样不相同。(我用的递归实现,也可以用栈来实现)

Python3 实现:

# @Time :2018/5/8

# @Author :LiuYinxing

class Solution:

def __init__(self, p):

self.n = len(p) # 获取n大小

self.minP = float("inf")

self.tempMinP = 0

self.p = p # 人员花费时间表

self.t = [[0] * self.n for _ in range(self.n)] # 标记数组

self.path = None

self.b = 0 # 记录是否已经走完一趟(0 无,1 走完一次)

def isok(self, k, i):

for j in range(self.n):

if self.t[k][j] == 1: return False # 第k人是否已经分配工作

for j in range(self.n):

if self.t[j][i] == 1: return False # 第i项工作是否已经被分配

return True

def getMinP(self, k=0):

if self.b == 1 and self.tempMinP >= self.minP: return # 进行减枝

if k == self.n:

self.b == 1

if self.tempMinP < self.minP:

self.minP = self.tempMinP

self.path = [v.index(1) + 1 for v in self.t] # 记录路径

return

for i in range(self.n):

if self.isok(k, i):

self.tempMinP += self.p[k][i]

self.t[k][i] = 1

self.getMinP(k + 1)

self.tempMinP -= self.p[k][i]

self.t[k][i] = 0

def getRul(self):

self.getMinP()

print('人员依次选择的工作为:',self.path)

print('最短时间为:',self.minP)

if __name__ == '__main__':

p = [[10, 2, 3], [2, 3, 4], [3, 4, 5]]

solu = Solution(p)

solu.getRul()

Python3实现,使用了numpy

# @Time :2018/5/8

# @Author :LiuYinxing

import numpy as np

class Solution:

def __init__(self, p):

self.n = len(p) # 获取n大小

self.minP = float("inf") # 记录最小的 花费

self.tempMinP = 0 # 保存中间值

self.p = p # 人员花费时间表

self.t = np.zeros((self.n, self.n)) # 标记数组全为零,

self.b = 0 # 记录是否已经走完一趟(0 无,1 走完一次)

self.path = [] # 负责记录路径

def getMinP(self, k=0):

if self.b == 1 and self.tempMinP >= self.minP: return # 进行减枝

if k == self.n:

self.b = 1

if self.tempMinP < self.minP:

self.minP = self.tempMinP

self.path = [np.argmax(v)+1 for v in self.t]

return

for i in range(self.n):

if (1 not in self.t[k]) and (1 not in self.t[:,i]): # 判断第k人是否已经分配工作,第i项工作是否已经被分配

self.tempMinP += self.p[k][i] # 添加一个值

self.t[k, i] = 1 # 标记此位置已经走过

self.getMinP(k + 1) # 添加下一个人员

self.tempMinP -= self.p[k][i] # 恢复中间变量

self.t[k, i] = 0 # 恢复位置

def getRul(self):

self.getMinP()

print('人员依次选择的工作为:',self.path)

print('最短时间为:',self.minP)

if __name__ == '__main__':

p = [[10,2,3], [2,3,4], [3,4,5]] # 9

# p = [[50,43,1,58,60], [87,22,5,62,71], [62,98,97,27,38], [56,57,96,73,71], [92,36,43,27,95]]

# p = [[50,43,1,58], [87,22,5,62], [62,98,97,27], [56,57,96,73]]

# p = [[8,6,13,4], [9,5,7,15], [5,2,7,11], [14,12,16,13]]

# p = [[85,45,12,16], [71,59,86,41], [88,45,23,76], [86,78,39,51]]

solu = Solution(p)

solu.getRul()

发现问题,可以留言指教哦。小白一个。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值